| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * xpath.c: XML Path Language implementation | 
 | 3 |  *          XPath is a language for addressing parts of an XML document, | 
 | 4 |  *          designed to be used by both XSLT and XPointer | 
 | 5 |  * | 
 | 6 |  * Reference: W3C Recommendation 16 November 1999 | 
 | 7 |  *     http://www.w3.org/TR/1999/REC-xpath-19991116 | 
 | 8 |  * Public reference: | 
 | 9 |  *     http://www.w3.org/TR/xpath | 
 | 10 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 11 |  * See Copyright for the status of this software | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 12 |  * | 
| Daniel Veillard | c5d6434 | 2001-06-24 12:13:24 +0000 | [diff] [blame] | 13 |  * Author: daniel@veillard.com | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 14 |  * | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 15 |  */ | 
 | 16 |  | 
| Daniel Veillard | 34ce8be | 2002-03-18 19:37:11 +0000 | [diff] [blame] | 17 | #define IN_LIBXML | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 18 | #include "libxml.h" | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 19 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 20 | #include <string.h> | 
 | 21 |  | 
 | 22 | #ifdef HAVE_SYS_TYPES_H | 
 | 23 | #include <sys/types.h> | 
 | 24 | #endif | 
 | 25 | #ifdef HAVE_MATH_H | 
 | 26 | #include <math.h> | 
 | 27 | #endif | 
 | 28 | #ifdef HAVE_FLOAT_H | 
 | 29 | #include <float.h> | 
 | 30 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 31 | #ifdef HAVE_CTYPE_H | 
 | 32 | #include <ctype.h> | 
 | 33 | #endif | 
| Daniel Veillard | 5792e16 | 2001-04-30 17:44:45 +0000 | [diff] [blame] | 34 | #ifdef HAVE_SIGNAL_H | 
| Daniel Veillard | b45c43b | 2001-04-28 17:02:11 +0000 | [diff] [blame] | 35 | #include <signal.h> | 
| Daniel Veillard | b45c43b | 2001-04-28 17:02:11 +0000 | [diff] [blame] | 36 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 37 |  | 
 | 38 | #include <libxml/xmlmemory.h> | 
 | 39 | #include <libxml/tree.h> | 
 | 40 | #include <libxml/valid.h> | 
 | 41 | #include <libxml/xpath.h> | 
 | 42 | #include <libxml/xpathInternals.h> | 
 | 43 | #include <libxml/parserInternals.h> | 
 | 44 | #include <libxml/hash.h> | 
 | 45 | #ifdef LIBXML_XPTR_ENABLED | 
 | 46 | #include <libxml/xpointer.h> | 
 | 47 | #endif | 
 | 48 | #ifdef LIBXML_DEBUG_ENABLED | 
 | 49 | #include <libxml/debugXML.h> | 
 | 50 | #endif | 
 | 51 | #include <libxml/xmlerror.h> | 
| Daniel Veillard | 8146394 | 2001-10-16 12:34:39 +0000 | [diff] [blame] | 52 | #include <libxml/threads.h> | 
| Daniel Veillard | 3c01b1d | 2001-10-17 15:58:35 +0000 | [diff] [blame] | 53 | #include <libxml/globals.h> | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 54 |  | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 55 | #define TODO 								\ | 
 | 56 |     xmlGenericError(xmlGenericErrorContext,				\ | 
 | 57 | 	    "Unimplemented block at %s:%d\n",				\ | 
 | 58 |             __FILE__, __LINE__); | 
 | 59 |  | 
| William M. Brack | d1757ab | 2004-10-02 22:07:48 +0000 | [diff] [blame] | 60 | /* | 
 | 61 |  * TODO: | 
 | 62 |  * There are a few spots where some tests are done which depend upon ascii | 
 | 63 |  * data.  These should be enhanced for full UTF8 support (see particularly | 
 | 64 |  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) | 
 | 65 |  */ | 
 | 66 |   | 
| Daniel Veillard | 4432df2 | 2003-09-28 18:58:27 +0000 | [diff] [blame] | 67 | #if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED) | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 68 | /************************************************************************ | 
 | 69 |  * 									* | 
 | 70 |  * 			Floating point stuff				* | 
 | 71 |  * 									* | 
 | 72 |  ************************************************************************/ | 
 | 73 |  | 
| Daniel Veillard | c0631a6 | 2001-09-20 13:56:06 +0000 | [diff] [blame] | 74 | #ifndef TRIO_REPLACE_STDIO | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 75 | #define TRIO_PUBLIC static | 
| Daniel Veillard | c0631a6 | 2001-09-20 13:56:06 +0000 | [diff] [blame] | 76 | #endif | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 77 | #include "trionan.c" | 
 | 78 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 79 | /* | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 80 |  * The lack of portability of this section of the libc is annoying ! | 
 | 81 |  */ | 
 | 82 | double xmlXPathNAN = 0; | 
 | 83 | double xmlXPathPINF = 1; | 
 | 84 | double xmlXPathNINF = -1; | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 85 | double xmlXPathNZERO = 0; | 
| Daniel Veillard | 20ee8c0 | 2001-10-05 09:18:14 +0000 | [diff] [blame] | 86 | static int xmlXPathInitialized = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 87 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 88 | /** | 
 | 89 |  * xmlXPathInit: | 
 | 90 |  * | 
 | 91 |  * Initialize the XPath environment | 
 | 92 |  */ | 
 | 93 | void | 
 | 94 | xmlXPathInit(void) { | 
| Daniel Veillard | 20ee8c0 | 2001-10-05 09:18:14 +0000 | [diff] [blame] | 95 |     if (xmlXPathInitialized) return; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 96 |  | 
| Bjorn Reese | 4502960 | 2001-08-21 09:23:53 +0000 | [diff] [blame] | 97 |     xmlXPathPINF = trio_pinf(); | 
 | 98 |     xmlXPathNINF = trio_ninf(); | 
 | 99 |     xmlXPathNAN = trio_nan(); | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 100 |     xmlXPathNZERO = trio_nzero(); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 101 |  | 
| Daniel Veillard | 20ee8c0 | 2001-10-05 09:18:14 +0000 | [diff] [blame] | 102 |     xmlXPathInitialized = 1; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 103 | } | 
 | 104 |  | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 105 | /** | 
 | 106 |  * xmlXPathIsNaN: | 
 | 107 |  * @val:  a double value | 
 | 108 |  * | 
 | 109 |  * Provides a portable isnan() function to detect whether a double | 
 | 110 |  * is a NotaNumber. Based on trio code | 
 | 111 |  * http://sourceforge.net/projects/ctrio/ | 
 | 112 |  *  | 
 | 113 |  * Returns 1 if the value is a NaN, 0 otherwise | 
 | 114 |  */ | 
 | 115 | int | 
 | 116 | xmlXPathIsNaN(double val) { | 
 | 117 |     return(trio_isnan(val)); | 
 | 118 | } | 
 | 119 |  | 
 | 120 | /** | 
 | 121 |  * xmlXPathIsInf: | 
 | 122 |  * @val:  a double value | 
 | 123 |  * | 
 | 124 |  * Provides a portable isinf() function to detect whether a double | 
 | 125 |  * is a +Infinite or -Infinite. Based on trio code | 
 | 126 |  * http://sourceforge.net/projects/ctrio/ | 
 | 127 |  *  | 
 | 128 |  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise | 
 | 129 |  */ | 
 | 130 | int | 
 | 131 | xmlXPathIsInf(double val) { | 
 | 132 |     return(trio_isinf(val)); | 
 | 133 | } | 
 | 134 |  | 
| Daniel Veillard | 4432df2 | 2003-09-28 18:58:27 +0000 | [diff] [blame] | 135 | #endif /* SCHEMAS or XPATH */ | 
 | 136 | #ifdef LIBXML_XPATH_ENABLED | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 137 | /** | 
 | 138 |  * xmlXPathGetSign: | 
 | 139 |  * @val:  a double value | 
 | 140 |  * | 
 | 141 |  * Provides a portable function to detect the sign of a double | 
 | 142 |  * Modified from trio code | 
 | 143 |  * http://sourceforge.net/projects/ctrio/ | 
 | 144 |  *  | 
 | 145 |  * Returns 1 if the value is Negative, 0 if positive | 
 | 146 |  */ | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 147 | static int | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 148 | xmlXPathGetSign(double val) { | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 149 |     return(trio_signbit(val)); | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 150 | } | 
 | 151 |  | 
 | 152 |  | 
| Daniel Veillard | d9d32ae | 2003-07-05 20:32:43 +0000 | [diff] [blame] | 153 | /* | 
 | 154 |  * TODO: when compatibility allows remove all "fake node libxslt" strings | 
 | 155 |  *       the test should just be name[0] = ' ' | 
 | 156 |  */ | 
 | 157 | /* #define DEBUG */ | 
 | 158 | /* #define DEBUG_STEP */ | 
 | 159 | /* #define DEBUG_STEP_NTH */ | 
 | 160 | /* #define DEBUG_EXPR */ | 
 | 161 | /* #define DEBUG_EVAL_COUNTS */ | 
 | 162 |  | 
 | 163 | static xmlNs xmlXPathXMLNamespaceStruct = { | 
 | 164 |     NULL, | 
 | 165 |     XML_NAMESPACE_DECL, | 
 | 166 |     XML_XML_NAMESPACE, | 
 | 167 |     BAD_CAST "xml", | 
 | 168 |     NULL | 
 | 169 | }; | 
 | 170 | static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; | 
 | 171 | #ifndef LIBXML_THREAD_ENABLED | 
 | 172 | /*  | 
 | 173 |  * Optimizer is disabled only when threaded apps are detected while | 
 | 174 |  * the library ain't compiled for thread safety. | 
 | 175 |  */ | 
 | 176 | static int xmlXPathDisableOptimizer = 0; | 
 | 177 | #endif | 
 | 178 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 179 | /************************************************************************ | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 180 |  *									* | 
 | 181 |  *			Error handling routines				* | 
 | 182 |  *									* | 
 | 183 |  ************************************************************************/ | 
 | 184 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 185 | /* | 
 | 186 |  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError | 
 | 187 |  */ | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 188 | static const char *xmlXPathErrorMessages[] = { | 
 | 189 |     "Ok\n", | 
 | 190 |     "Number encoding\n", | 
 | 191 |     "Unfinished literal\n", | 
 | 192 |     "Start of literal\n", | 
 | 193 |     "Expected $ for variable reference\n", | 
 | 194 |     "Undefined variable\n", | 
 | 195 |     "Invalid predicate\n", | 
 | 196 |     "Invalid expression\n", | 
 | 197 |     "Missing closing curly brace\n", | 
 | 198 |     "Unregistered function\n", | 
 | 199 |     "Invalid operand\n", | 
 | 200 |     "Invalid type\n", | 
 | 201 |     "Invalid number of arguments\n", | 
 | 202 |     "Invalid context size\n", | 
 | 203 |     "Invalid context position\n", | 
 | 204 |     "Memory allocation error\n", | 
 | 205 |     "Syntax error\n", | 
 | 206 |     "Resource error\n", | 
 | 207 |     "Sub resource error\n", | 
 | 208 |     "Undefined namespace prefix\n", | 
 | 209 |     "Encoding error\n", | 
| Daniel Veillard | 57b2516 | 2004-11-06 14:50:18 +0000 | [diff] [blame] | 210 |     "Char out of XML range\n", | 
 | 211 |     "Invalid or inclomplete context\n" | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 212 | }; | 
 | 213 |  | 
 | 214 |  | 
 | 215 | /** | 
 | 216 |  * xmlXPathErrMemory: | 
 | 217 |  * @ctxt:  an XPath context | 
 | 218 |  * @extra:  extra informations | 
 | 219 |  * | 
 | 220 |  * Handle a redefinition of attribute error | 
 | 221 |  */ | 
 | 222 | static void | 
 | 223 | xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) | 
 | 224 | { | 
 | 225 |     if (ctxt != NULL) { | 
 | 226 |         if (extra) { | 
 | 227 |             xmlChar buf[200]; | 
 | 228 |  | 
 | 229 |             xmlStrPrintf(buf, 200, | 
 | 230 |                          BAD_CAST "Memory allocation failed : %s\n", | 
 | 231 |                          extra); | 
 | 232 |             ctxt->lastError.message = (char *) xmlStrdup(buf); | 
 | 233 |         } else { | 
 | 234 |             ctxt->lastError.message = (char *) | 
 | 235 | 	       xmlStrdup(BAD_CAST "Memory allocation failed\n"); | 
 | 236 |         } | 
 | 237 |         ctxt->lastError.domain = XML_FROM_XPATH; | 
 | 238 |         ctxt->lastError.code = XML_ERR_NO_MEMORY; | 
 | 239 | 	if (ctxt->error != NULL) | 
 | 240 | 	    ctxt->error(ctxt->userData, &ctxt->lastError); | 
 | 241 |     } else { | 
 | 242 |         if (extra) | 
| Daniel Veillard | 659e71e | 2003-10-10 14:10:40 +0000 | [diff] [blame] | 243 |             __xmlRaiseError(NULL, NULL, NULL, | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 244 |                             NULL, NULL, XML_FROM_XPATH, | 
 | 245 |                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, | 
 | 246 |                             extra, NULL, NULL, 0, 0, | 
 | 247 |                             "Memory allocation failed : %s\n", extra); | 
 | 248 |         else | 
| Daniel Veillard | 659e71e | 2003-10-10 14:10:40 +0000 | [diff] [blame] | 249 |             __xmlRaiseError(NULL, NULL, NULL, | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 250 |                             NULL, NULL, XML_FROM_XPATH, | 
 | 251 |                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, | 
 | 252 |                             NULL, NULL, NULL, 0, 0, | 
 | 253 |                             "Memory allocation failed\n"); | 
 | 254 |     } | 
 | 255 | } | 
 | 256 |  | 
 | 257 | /** | 
| Daniel Veillard | 8de5c0b | 2004-10-07 13:14:19 +0000 | [diff] [blame] | 258 |  * xmlXPathPErrMemory: | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 259 |  * @ctxt:  an XPath parser context | 
 | 260 |  * @extra:  extra informations | 
 | 261 |  * | 
 | 262 |  * Handle a redefinition of attribute error | 
 | 263 |  */ | 
 | 264 | static void | 
 | 265 | xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) | 
 | 266 | { | 
 | 267 |     ctxt->error = XPATH_MEMORY_ERROR; | 
 | 268 |     if (ctxt == NULL) | 
 | 269 | 	xmlXPathErrMemory(NULL, extra); | 
 | 270 |     else | 
 | 271 | 	xmlXPathErrMemory(ctxt->context, extra); | 
 | 272 | } | 
 | 273 |  | 
 | 274 | /** | 
 | 275 |  * xmlXPathErr: | 
 | 276 |  * @ctxt:  a XPath parser context | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 277 |  * @error:  the error code | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 278 |  * | 
 | 279 |  * Handle a Relax NG Parsing error | 
 | 280 |  */ | 
 | 281 | void | 
 | 282 | xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) | 
 | 283 | { | 
| Daniel Veillard | f88d8cf | 2003-12-08 10:25:02 +0000 | [diff] [blame] | 284 |     if (ctxt == NULL) { | 
| Daniel Veillard | 659e71e | 2003-10-10 14:10:40 +0000 | [diff] [blame] | 285 | 	__xmlRaiseError(NULL, NULL, NULL, | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 286 | 			NULL, NULL, XML_FROM_XPATH, | 
 | 287 | 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, | 
 | 288 | 			XML_ERR_ERROR, NULL, 0, | 
 | 289 | 			NULL, NULL, NULL, 0, 0, | 
 | 290 | 			xmlXPathErrorMessages[error]); | 
 | 291 | 	return; | 
 | 292 |     } | 
| Daniel Veillard | f88d8cf | 2003-12-08 10:25:02 +0000 | [diff] [blame] | 293 |     ctxt->error = error; | 
 | 294 |     if (ctxt->context == NULL) { | 
 | 295 | 	__xmlRaiseError(NULL, NULL, NULL, | 
 | 296 | 			NULL, NULL, XML_FROM_XPATH, | 
 | 297 | 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, | 
 | 298 | 			XML_ERR_ERROR, NULL, 0, | 
 | 299 | 			(const char *) ctxt->base, NULL, NULL, | 
 | 300 | 			ctxt->cur - ctxt->base, 0, | 
 | 301 | 			xmlXPathErrorMessages[error]); | 
 | 302 | 	return; | 
 | 303 |     } | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 304 |     ctxt->context->lastError.domain = XML_FROM_XPATH; | 
 | 305 |     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - | 
 | 306 |                            XPATH_EXPRESSION_OK; | 
| Daniel Veillard | fcf719c | 2003-10-10 11:42:17 +0000 | [diff] [blame] | 307 |     ctxt->context->lastError.level = XML_ERR_ERROR; | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 308 |     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); | 
 | 309 |     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; | 
 | 310 |     ctxt->context->lastError.node = ctxt->context->debugNode; | 
 | 311 |     if (ctxt->context->error != NULL) { | 
 | 312 | 	ctxt->context->error(ctxt->context->userData, | 
 | 313 | 	                     &ctxt->context->lastError); | 
 | 314 |     } else { | 
| Daniel Veillard | 659e71e | 2003-10-10 14:10:40 +0000 | [diff] [blame] | 315 | 	__xmlRaiseError(NULL, NULL, NULL, | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 316 | 			NULL, ctxt->context->debugNode, XML_FROM_XPATH, | 
 | 317 | 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, | 
 | 318 | 			XML_ERR_ERROR, NULL, 0, | 
 | 319 | 			(const char *) ctxt->base, NULL, NULL, | 
 | 320 | 			ctxt->cur - ctxt->base, 0, | 
 | 321 | 			xmlXPathErrorMessages[error]); | 
 | 322 |     } | 
 | 323 |  | 
 | 324 | } | 
 | 325 |  | 
 | 326 | /** | 
 | 327 |  * xmlXPatherror: | 
 | 328 |  * @ctxt:  the XPath Parser context | 
 | 329 |  * @file:  the file name | 
 | 330 |  * @line:  the line number | 
 | 331 |  * @no:  the error number | 
 | 332 |  * | 
 | 333 |  * Formats an error message. | 
 | 334 |  */ | 
 | 335 | void | 
 | 336 | xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, | 
 | 337 |               int line ATTRIBUTE_UNUSED, int no) { | 
 | 338 |     xmlXPathErr(ctxt, no); | 
 | 339 | } | 
 | 340 |  | 
 | 341 |  | 
 | 342 | /************************************************************************ | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 343 |  * 									* | 
 | 344 |  * 			Parser Types					* | 
 | 345 |  * 									* | 
 | 346 |  ************************************************************************/ | 
 | 347 |  | 
 | 348 | /* | 
 | 349 |  * Types are private: | 
 | 350 |  */ | 
 | 351 |  | 
 | 352 | typedef enum { | 
 | 353 |     XPATH_OP_END=0, | 
 | 354 |     XPATH_OP_AND, | 
 | 355 |     XPATH_OP_OR, | 
 | 356 |     XPATH_OP_EQUAL, | 
 | 357 |     XPATH_OP_CMP, | 
 | 358 |     XPATH_OP_PLUS, | 
 | 359 |     XPATH_OP_MULT, | 
 | 360 |     XPATH_OP_UNION, | 
 | 361 |     XPATH_OP_ROOT, | 
 | 362 |     XPATH_OP_NODE, | 
 | 363 |     XPATH_OP_RESET, | 
 | 364 |     XPATH_OP_COLLECT, | 
 | 365 |     XPATH_OP_VALUE, | 
 | 366 |     XPATH_OP_VARIABLE, | 
 | 367 |     XPATH_OP_FUNCTION, | 
 | 368 |     XPATH_OP_ARG, | 
 | 369 |     XPATH_OP_PREDICATE, | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 370 |     XPATH_OP_FILTER, | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 371 |     XPATH_OP_SORT | 
 | 372 | #ifdef LIBXML_XPTR_ENABLED | 
 | 373 |     ,XPATH_OP_RANGETO | 
 | 374 | #endif | 
 | 375 | } xmlXPathOp; | 
 | 376 |  | 
 | 377 | typedef enum { | 
 | 378 |     AXIS_ANCESTOR = 1, | 
 | 379 |     AXIS_ANCESTOR_OR_SELF, | 
 | 380 |     AXIS_ATTRIBUTE, | 
 | 381 |     AXIS_CHILD, | 
 | 382 |     AXIS_DESCENDANT, | 
 | 383 |     AXIS_DESCENDANT_OR_SELF, | 
 | 384 |     AXIS_FOLLOWING, | 
 | 385 |     AXIS_FOLLOWING_SIBLING, | 
 | 386 |     AXIS_NAMESPACE, | 
 | 387 |     AXIS_PARENT, | 
 | 388 |     AXIS_PRECEDING, | 
 | 389 |     AXIS_PRECEDING_SIBLING, | 
 | 390 |     AXIS_SELF | 
 | 391 | } xmlXPathAxisVal; | 
 | 392 |  | 
 | 393 | typedef enum { | 
 | 394 |     NODE_TEST_NONE = 0, | 
 | 395 |     NODE_TEST_TYPE = 1, | 
 | 396 |     NODE_TEST_PI = 2, | 
 | 397 |     NODE_TEST_ALL = 3, | 
 | 398 |     NODE_TEST_NS = 4, | 
 | 399 |     NODE_TEST_NAME = 5 | 
 | 400 | } xmlXPathTestVal; | 
 | 401 |  | 
 | 402 | typedef enum { | 
 | 403 |     NODE_TYPE_NODE = 0, | 
 | 404 |     NODE_TYPE_COMMENT = XML_COMMENT_NODE, | 
 | 405 |     NODE_TYPE_TEXT = XML_TEXT_NODE, | 
 | 406 |     NODE_TYPE_PI = XML_PI_NODE | 
 | 407 | } xmlXPathTypeVal; | 
 | 408 |  | 
 | 409 |  | 
 | 410 | typedef struct _xmlXPathStepOp xmlXPathStepOp; | 
 | 411 | typedef xmlXPathStepOp *xmlXPathStepOpPtr; | 
 | 412 | struct _xmlXPathStepOp { | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 413 |     xmlXPathOp op;		/* The identifier of the operation */ | 
 | 414 |     int ch1;			/* First child */ | 
 | 415 |     int ch2;			/* Second child */ | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 416 |     int value; | 
 | 417 |     int value2; | 
 | 418 |     int value3; | 
 | 419 |     void *value4; | 
 | 420 |     void *value5; | 
| Daniel Veillard | e39a93d | 2001-04-28 14:35:02 +0000 | [diff] [blame] | 421 |     void *cache; | 
| Daniel Veillard | 42596ad | 2001-05-22 16:57:14 +0000 | [diff] [blame] | 422 |     void *cacheURI; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 423 | }; | 
 | 424 |  | 
 | 425 | struct _xmlXPathCompExpr { | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 426 |     int nbStep;			/* Number of steps in this expression */ | 
 | 427 |     int maxStep;		/* Maximum number of steps allocated */ | 
 | 428 |     xmlXPathStepOp *steps;	/* ops for computation of this expression */ | 
 | 429 |     int last;			/* index of last step in expression */ | 
 | 430 |     xmlChar *expr;		/* the expression being computed */ | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 431 |     xmlDictPtr dict;		/* the dictionnary to use if any */ | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 432 | #ifdef DEBUG_EVAL_COUNTS | 
 | 433 |     int nb; | 
 | 434 |     xmlChar *string; | 
 | 435 | #endif | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 436 | }; | 
 | 437 |  | 
 | 438 | /************************************************************************ | 
 | 439 |  * 									* | 
 | 440 |  * 			Parser Type functions 				* | 
 | 441 |  * 									* | 
 | 442 |  ************************************************************************/ | 
 | 443 |  | 
 | 444 | /** | 
 | 445 |  * xmlXPathNewCompExpr: | 
 | 446 |  * | 
 | 447 |  * Create a new Xpath component | 
 | 448 |  * | 
 | 449 |  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error | 
 | 450 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 451 | static xmlXPathCompExprPtr | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 452 | xmlXPathNewCompExpr(void) { | 
 | 453 |     xmlXPathCompExprPtr cur; | 
 | 454 |  | 
 | 455 |     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); | 
 | 456 |     if (cur == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 457 |         xmlXPathErrMemory(NULL, "allocating component\n"); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 458 | 	return(NULL); | 
 | 459 |     } | 
 | 460 |     memset(cur, 0, sizeof(xmlXPathCompExpr)); | 
 | 461 |     cur->maxStep = 10; | 
 | 462 |     cur->nbStep = 0; | 
 | 463 |     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * | 
 | 464 | 	                                   sizeof(xmlXPathStepOp)); | 
 | 465 |     if (cur->steps == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 466 |         xmlXPathErrMemory(NULL, "allocating steps\n"); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 467 | 	xmlFree(cur); | 
 | 468 | 	return(NULL); | 
 | 469 |     } | 
 | 470 |     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); | 
 | 471 |     cur->last = -1; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 472 | #ifdef DEBUG_EVAL_COUNTS | 
 | 473 |     cur->nb = 0; | 
 | 474 | #endif | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 475 |     return(cur); | 
 | 476 | } | 
 | 477 |  | 
 | 478 | /** | 
 | 479 |  * xmlXPathFreeCompExpr: | 
 | 480 |  * @comp:  an XPATH comp | 
 | 481 |  * | 
 | 482 |  * Free up the memory allocated by @comp | 
 | 483 |  */ | 
 | 484 | void | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 485 | xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) | 
 | 486 | { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 487 |     xmlXPathStepOpPtr op; | 
 | 488 |     int i; | 
 | 489 |  | 
 | 490 |     if (comp == NULL) | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 491 |         return; | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 492 |     if (comp->dict == NULL) { | 
 | 493 | 	for (i = 0; i < comp->nbStep; i++) { | 
 | 494 | 	    op = &comp->steps[i]; | 
 | 495 | 	    if (op->value4 != NULL) { | 
 | 496 | 		if (op->op == XPATH_OP_VALUE) | 
 | 497 | 		    xmlXPathFreeObject(op->value4); | 
 | 498 | 		else | 
 | 499 | 		    xmlFree(op->value4); | 
 | 500 | 	    } | 
 | 501 | 	    if (op->value5 != NULL) | 
 | 502 | 		xmlFree(op->value5); | 
 | 503 | 	} | 
 | 504 |     } else { | 
 | 505 | 	for (i = 0; i < comp->nbStep; i++) { | 
 | 506 | 	    op = &comp->steps[i]; | 
 | 507 | 	    if (op->value4 != NULL) { | 
 | 508 | 		if (op->op == XPATH_OP_VALUE) | 
 | 509 | 		    xmlXPathFreeObject(op->value4); | 
 | 510 | 	    } | 
 | 511 | 	} | 
 | 512 |         xmlDictFree(comp->dict); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 513 |     } | 
 | 514 |     if (comp->steps != NULL) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 515 |         xmlFree(comp->steps); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 516 |     } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 517 | #ifdef DEBUG_EVAL_COUNTS | 
 | 518 |     if (comp->string != NULL) { | 
 | 519 |         xmlFree(comp->string); | 
 | 520 |     } | 
 | 521 | #endif | 
| Daniel Veillard | 118aed7 | 2002-09-24 14:13:13 +0000 | [diff] [blame] | 522 |     if (comp->expr != NULL) { | 
 | 523 |         xmlFree(comp->expr); | 
 | 524 |     } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 525 |  | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 526 |     xmlFree(comp); | 
 | 527 | } | 
 | 528 |  | 
 | 529 | /** | 
 | 530 |  * xmlXPathCompExprAdd: | 
 | 531 |  * @comp:  the compiled expression | 
 | 532 |  * @ch1: first child index | 
 | 533 |  * @ch2: second child index | 
 | 534 |  * @op:  an op | 
 | 535 |  * @value:  the first int value | 
 | 536 |  * @value2:  the second int value | 
 | 537 |  * @value3:  the third int value | 
 | 538 |  * @value4:  the first string value | 
 | 539 |  * @value5:  the second string value | 
 | 540 |  * | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 541 |  * Add a step to an XPath Compiled Expression | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 542 |  * | 
 | 543 |  * Returns -1 in case of failure, the index otherwise | 
 | 544 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 545 | static int | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 546 | xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, | 
 | 547 |    xmlXPathOp op, int value, | 
 | 548 |    int value2, int value3, void *value4, void *value5) { | 
 | 549 |     if (comp->nbStep >= comp->maxStep) { | 
 | 550 | 	xmlXPathStepOp *real; | 
 | 551 |  | 
 | 552 | 	comp->maxStep *= 2; | 
 | 553 | 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps, | 
 | 554 | 		                      comp->maxStep * sizeof(xmlXPathStepOp)); | 
 | 555 | 	if (real == NULL) { | 
 | 556 | 	    comp->maxStep /= 2; | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 557 | 	    xmlXPathErrMemory(NULL, "adding step\n"); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 558 | 	    return(-1); | 
 | 559 | 	} | 
 | 560 | 	comp->steps = real; | 
 | 561 |     } | 
 | 562 |     comp->last = comp->nbStep; | 
 | 563 |     comp->steps[comp->nbStep].ch1 = ch1; | 
 | 564 |     comp->steps[comp->nbStep].ch2 = ch2; | 
 | 565 |     comp->steps[comp->nbStep].op = op; | 
 | 566 |     comp->steps[comp->nbStep].value = value; | 
 | 567 |     comp->steps[comp->nbStep].value2 = value2; | 
 | 568 |     comp->steps[comp->nbStep].value3 = value3; | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 569 |     if ((comp->dict != NULL) && | 
 | 570 |         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || | 
 | 571 | 	 (op == XPATH_OP_COLLECT))) { | 
 | 572 |         if (value4 != NULL) { | 
| Daniel Veillard | b337795 | 2004-02-09 12:48:55 +0000 | [diff] [blame] | 573 | 	    comp->steps[comp->nbStep].value4 = (xmlChar *) | 
| William M. Brack | c07ed5e | 2004-01-30 07:52:48 +0000 | [diff] [blame] | 574 | 	        (void *)xmlDictLookup(comp->dict, value4, -1); | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 575 | 	    xmlFree(value4); | 
 | 576 | 	} else | 
 | 577 | 	    comp->steps[comp->nbStep].value4 = NULL; | 
 | 578 |         if (value5 != NULL) { | 
| Daniel Veillard | b337795 | 2004-02-09 12:48:55 +0000 | [diff] [blame] | 579 | 	    comp->steps[comp->nbStep].value5 = (xmlChar *) | 
| William M. Brack | c07ed5e | 2004-01-30 07:52:48 +0000 | [diff] [blame] | 580 | 	        (void *)xmlDictLookup(comp->dict, value5, -1); | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 581 | 	    xmlFree(value5); | 
 | 582 | 	} else | 
 | 583 | 	    comp->steps[comp->nbStep].value5 = NULL; | 
 | 584 |     } else { | 
 | 585 | 	comp->steps[comp->nbStep].value4 = value4; | 
 | 586 | 	comp->steps[comp->nbStep].value5 = value5; | 
 | 587 |     } | 
| Daniel Veillard | e39a93d | 2001-04-28 14:35:02 +0000 | [diff] [blame] | 588 |     comp->steps[comp->nbStep].cache = NULL; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 589 |     return(comp->nbStep++); | 
 | 590 | } | 
 | 591 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 592 | /** | 
 | 593 |  * xmlXPathCompSwap: | 
 | 594 |  * @comp:  the compiled expression | 
 | 595 |  * @op: operation index | 
 | 596 |  * | 
 | 597 |  * Swaps 2 operations in the compiled expression | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 598 |  */ | 
 | 599 | static void | 
 | 600 | xmlXPathCompSwap(xmlXPathStepOpPtr op) { | 
 | 601 |     int tmp; | 
 | 602 |  | 
| Daniel Veillard | bc6f759 | 2002-04-16 07:49:59 +0000 | [diff] [blame] | 603 | #ifndef LIBXML_THREAD_ENABLED | 
| Daniel Veillard | 8146394 | 2001-10-16 12:34:39 +0000 | [diff] [blame] | 604 |     /* | 
 | 605 |      * Since this manipulates possibly shared variables, this is | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 606 |      * disabled if one detects that the library is used in a multithreaded | 
| Daniel Veillard | 8146394 | 2001-10-16 12:34:39 +0000 | [diff] [blame] | 607 |      * application | 
 | 608 |      */ | 
 | 609 |     if (xmlXPathDisableOptimizer) | 
 | 610 | 	return; | 
 | 611 | #endif | 
 | 612 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 613 |     tmp = op->ch1; | 
 | 614 |     op->ch1 = op->ch2; | 
 | 615 |     op->ch2 = tmp; | 
 | 616 | } | 
 | 617 |  | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 618 | #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\ | 
 | 619 |     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\ | 
 | 620 | 	                (op), (val), (val2), (val3), (val4), (val5)) | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 621 | #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\ | 
 | 622 |     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\ | 
 | 623 | 	                (op), (val), (val2), (val3), (val4), (val5)) | 
 | 624 |  | 
 | 625 | #define PUSH_LEAVE_EXPR(op, val, val2) 					\ | 
 | 626 | xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) | 
 | 627 |  | 
 | 628 | #define PUSH_UNARY_EXPR(op, ch, val, val2) 				\ | 
 | 629 | xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) | 
 | 630 |  | 
 | 631 | #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) 			\ | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 632 | xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\ | 
 | 633 | 			(val), (val2), 0 ,NULL ,NULL) | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 634 |  | 
 | 635 | /************************************************************************ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 636 |  *									* | 
 | 637 |  * 		Debugging related functions				* | 
 | 638 |  *									* | 
 | 639 |  ************************************************************************/ | 
 | 640 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 641 | #define STRANGE 							\ | 
 | 642 |     xmlGenericError(xmlGenericErrorContext,				\ | 
 | 643 | 	    "Internal error at %s:%d\n",				\ | 
 | 644 |             __FILE__, __LINE__); | 
 | 645 |  | 
 | 646 | #ifdef LIBXML_DEBUG_ENABLED | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 647 | static void | 
 | 648 | xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 649 |     int i; | 
 | 650 |     char shift[100]; | 
 | 651 |  | 
 | 652 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 653 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 654 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 655 |     if (cur == NULL) { | 
 | 656 | 	fprintf(output, shift); | 
 | 657 | 	fprintf(output, "Node is NULL !\n"); | 
 | 658 | 	return; | 
 | 659 |          | 
 | 660 |     } | 
 | 661 |  | 
 | 662 |     if ((cur->type == XML_DOCUMENT_NODE) || | 
 | 663 | 	     (cur->type == XML_HTML_DOCUMENT_NODE)) { | 
 | 664 | 	fprintf(output, shift); | 
 | 665 | 	fprintf(output, " /\n"); | 
 | 666 |     } else if (cur->type == XML_ATTRIBUTE_NODE) | 
 | 667 | 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); | 
 | 668 |     else | 
 | 669 | 	xmlDebugDumpOneNode(output, cur, depth); | 
 | 670 | } | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 671 | static void | 
 | 672 | xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { | 
| Daniel Veillard | f7cd481 | 2001-02-23 18:44:52 +0000 | [diff] [blame] | 673 |     xmlNodePtr tmp; | 
 | 674 |     int i; | 
 | 675 |     char shift[100]; | 
 | 676 |  | 
 | 677 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 678 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 679 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 680 |     if (cur == NULL) { | 
 | 681 | 	fprintf(output, shift); | 
 | 682 | 	fprintf(output, "Node is NULL !\n"); | 
 | 683 | 	return; | 
 | 684 |          | 
 | 685 |     } | 
 | 686 |  | 
 | 687 |     while (cur != NULL) { | 
 | 688 | 	tmp = cur; | 
 | 689 | 	cur = cur->next; | 
 | 690 | 	xmlDebugDumpOneNode(output, tmp, depth); | 
 | 691 |     } | 
 | 692 | } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 693 |  | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 694 | static void | 
 | 695 | xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 696 |     int i; | 
 | 697 |     char shift[100]; | 
 | 698 |  | 
 | 699 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 700 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 701 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 702 |  | 
 | 703 |     if (cur == NULL) { | 
 | 704 | 	fprintf(output, shift); | 
 | 705 | 	fprintf(output, "NodeSet is NULL !\n"); | 
 | 706 | 	return; | 
 | 707 |          | 
 | 708 |     } | 
 | 709 |  | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 710 |     if (cur != NULL) { | 
 | 711 | 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); | 
 | 712 | 	for (i = 0;i < cur->nodeNr;i++) { | 
 | 713 | 	    fprintf(output, shift); | 
 | 714 | 	    fprintf(output, "%d", i + 1); | 
 | 715 | 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); | 
 | 716 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 717 |     } | 
 | 718 | } | 
 | 719 |  | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 720 | static void | 
 | 721 | xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { | 
| Daniel Veillard | f7cd481 | 2001-02-23 18:44:52 +0000 | [diff] [blame] | 722 |     int i; | 
 | 723 |     char shift[100]; | 
 | 724 |  | 
 | 725 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 726 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 727 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 728 |  | 
 | 729 |     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { | 
 | 730 | 	fprintf(output, shift); | 
 | 731 | 	fprintf(output, "Value Tree is NULL !\n"); | 
 | 732 | 	return; | 
 | 733 |          | 
 | 734 |     } | 
 | 735 |  | 
 | 736 |     fprintf(output, shift); | 
 | 737 |     fprintf(output, "%d", i + 1); | 
 | 738 |     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); | 
 | 739 | } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 740 | #if defined(LIBXML_XPTR_ENABLED) | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 741 | static void | 
 | 742 | xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 743 |     int i; | 
 | 744 |     char shift[100]; | 
 | 745 |  | 
 | 746 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 747 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 748 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 749 |  | 
 | 750 |     if (cur == NULL) { | 
 | 751 | 	fprintf(output, shift); | 
 | 752 | 	fprintf(output, "LocationSet is NULL !\n"); | 
 | 753 | 	return; | 
 | 754 |          | 
 | 755 |     } | 
 | 756 |  | 
 | 757 |     for (i = 0;i < cur->locNr;i++) { | 
 | 758 | 	fprintf(output, shift); | 
 | 759 |         fprintf(output, "%d : ", i + 1); | 
 | 760 | 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); | 
 | 761 |     } | 
 | 762 | } | 
| Daniel Veillard | 017b108 | 2001-06-21 11:20:21 +0000 | [diff] [blame] | 763 | #endif /* LIBXML_XPTR_ENABLED */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 764 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 765 | /** | 
 | 766 |  * xmlXPathDebugDumpObject: | 
 | 767 |  * @output:  the FILE * to dump the output | 
 | 768 |  * @cur:  the object to inspect | 
 | 769 |  * @depth:  indentation level | 
 | 770 |  * | 
 | 771 |  * Dump the content of the object for debugging purposes | 
 | 772 |  */ | 
 | 773 | void | 
 | 774 | xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 775 |     int i; | 
 | 776 |     char shift[100]; | 
 | 777 |  | 
 | 778 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 779 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 780 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 781 |  | 
 | 782 |     fprintf(output, shift); | 
 | 783 |  | 
 | 784 |     if (cur == NULL) { | 
 | 785 |         fprintf(output, "Object is empty (NULL)\n"); | 
 | 786 | 	return; | 
 | 787 |     } | 
 | 788 |     switch(cur->type) { | 
 | 789 |         case XPATH_UNDEFINED: | 
 | 790 | 	    fprintf(output, "Object is uninitialized\n"); | 
 | 791 | 	    break; | 
 | 792 |         case XPATH_NODESET: | 
 | 793 | 	    fprintf(output, "Object is a Node Set :\n"); | 
 | 794 | 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); | 
 | 795 | 	    break; | 
 | 796 | 	case XPATH_XSLT_TREE: | 
 | 797 | 	    fprintf(output, "Object is an XSLT value tree :\n"); | 
| Daniel Veillard | f7cd481 | 2001-02-23 18:44:52 +0000 | [diff] [blame] | 798 | 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 799 | 	    break; | 
 | 800 |         case XPATH_BOOLEAN: | 
 | 801 | 	    fprintf(output, "Object is a Boolean : "); | 
 | 802 | 	    if (cur->boolval) fprintf(output, "true\n"); | 
 | 803 | 	    else fprintf(output, "false\n"); | 
 | 804 | 	    break; | 
 | 805 |         case XPATH_NUMBER: | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 806 | 	    switch (xmlXPathIsInf(cur->floatval)) { | 
| Daniel Veillard | 357c960 | 2001-05-03 10:49:20 +0000 | [diff] [blame] | 807 | 	    case 1: | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 808 | 		fprintf(output, "Object is a number : Infinity\n"); | 
| Daniel Veillard | 357c960 | 2001-05-03 10:49:20 +0000 | [diff] [blame] | 809 | 		break; | 
 | 810 | 	    case -1: | 
 | 811 | 		fprintf(output, "Object is a number : -Infinity\n"); | 
 | 812 | 		break; | 
 | 813 | 	    default: | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 814 | 		if (xmlXPathIsNaN(cur->floatval)) { | 
| Daniel Veillard | 357c960 | 2001-05-03 10:49:20 +0000 | [diff] [blame] | 815 | 		    fprintf(output, "Object is a number : NaN\n"); | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 816 | 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { | 
 | 817 | 		    fprintf(output, "Object is a number : 0\n"); | 
| Daniel Veillard | 357c960 | 2001-05-03 10:49:20 +0000 | [diff] [blame] | 818 | 		} else { | 
 | 819 | 		    fprintf(output, "Object is a number : %0g\n", cur->floatval); | 
 | 820 | 		} | 
 | 821 | 	    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 822 | 	    break; | 
 | 823 |         case XPATH_STRING: | 
 | 824 | 	    fprintf(output, "Object is a string : "); | 
 | 825 | 	    xmlDebugDumpString(output, cur->stringval); | 
 | 826 | 	    fprintf(output, "\n"); | 
 | 827 | 	    break; | 
 | 828 | 	case XPATH_POINT: | 
 | 829 | 	    fprintf(output, "Object is a point : index %d in node", cur->index); | 
 | 830 | 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); | 
 | 831 | 	    fprintf(output, "\n"); | 
 | 832 | 	    break; | 
 | 833 | 	case XPATH_RANGE: | 
 | 834 | 	    if ((cur->user2 == NULL) || | 
 | 835 | 		((cur->user2 == cur->user) && (cur->index == cur->index2))) { | 
 | 836 | 		fprintf(output, "Object is a collapsed range :\n"); | 
 | 837 | 		fprintf(output, shift); | 
 | 838 | 		if (cur->index >= 0) | 
 | 839 | 		    fprintf(output, "index %d in ", cur->index); | 
 | 840 | 		fprintf(output, "node\n"); | 
 | 841 | 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, | 
 | 842 | 			              depth + 1); | 
 | 843 | 	    } else  { | 
 | 844 | 		fprintf(output, "Object is a range :\n"); | 
 | 845 | 		fprintf(output, shift); | 
 | 846 | 		fprintf(output, "From "); | 
 | 847 | 		if (cur->index >= 0) | 
 | 848 | 		    fprintf(output, "index %d in ", cur->index); | 
 | 849 | 		fprintf(output, "node\n"); | 
 | 850 | 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, | 
 | 851 | 			              depth + 1); | 
 | 852 | 		fprintf(output, shift); | 
 | 853 | 		fprintf(output, "To "); | 
 | 854 | 		if (cur->index2 >= 0) | 
 | 855 | 		    fprintf(output, "index %d in ", cur->index2); | 
 | 856 | 		fprintf(output, "node\n"); | 
 | 857 | 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, | 
 | 858 | 			              depth + 1); | 
 | 859 | 		fprintf(output, "\n"); | 
 | 860 | 	    } | 
 | 861 | 	    break; | 
 | 862 | 	case XPATH_LOCATIONSET: | 
 | 863 | #if defined(LIBXML_XPTR_ENABLED) | 
 | 864 | 	    fprintf(output, "Object is a Location Set:\n"); | 
 | 865 | 	    xmlXPathDebugDumpLocationSet(output, | 
 | 866 | 		    (xmlLocationSetPtr) cur->user, depth); | 
 | 867 | #endif | 
 | 868 | 	    break; | 
 | 869 | 	case XPATH_USERS: | 
 | 870 | 	    fprintf(output, "Object is user defined\n"); | 
 | 871 | 	    break; | 
 | 872 |     } | 
 | 873 | } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 874 |  | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 875 | static void | 
 | 876 | xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 877 | 	                     xmlXPathStepOpPtr op, int depth) { | 
 | 878 |     int i; | 
 | 879 |     char shift[100]; | 
 | 880 |  | 
 | 881 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 882 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 883 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 884 |  | 
 | 885 |     fprintf(output, shift); | 
 | 886 |     if (op == NULL) { | 
 | 887 | 	fprintf(output, "Step is NULL\n"); | 
 | 888 | 	return; | 
 | 889 |     } | 
 | 890 |     switch (op->op) { | 
 | 891 |         case XPATH_OP_END: | 
 | 892 | 	    fprintf(output, "END"); break; | 
 | 893 |         case XPATH_OP_AND: | 
 | 894 | 	    fprintf(output, "AND"); break; | 
 | 895 |         case XPATH_OP_OR: | 
 | 896 | 	    fprintf(output, "OR"); break; | 
 | 897 |         case XPATH_OP_EQUAL: | 
 | 898 | 	     if (op->value) | 
 | 899 | 		 fprintf(output, "EQUAL ="); | 
 | 900 | 	     else | 
 | 901 | 		 fprintf(output, "EQUAL !="); | 
 | 902 | 	     break; | 
 | 903 |         case XPATH_OP_CMP: | 
 | 904 | 	     if (op->value) | 
 | 905 | 		 fprintf(output, "CMP <"); | 
 | 906 | 	     else | 
 | 907 | 		 fprintf(output, "CMP >"); | 
 | 908 | 	     if (!op->value2) | 
 | 909 | 		 fprintf(output, "="); | 
 | 910 | 	     break; | 
 | 911 |         case XPATH_OP_PLUS: | 
 | 912 | 	     if (op->value == 0) | 
 | 913 | 		 fprintf(output, "PLUS -"); | 
 | 914 | 	     else if (op->value == 1) | 
 | 915 | 		 fprintf(output, "PLUS +"); | 
 | 916 | 	     else if (op->value == 2) | 
 | 917 | 		 fprintf(output, "PLUS unary -"); | 
 | 918 | 	     else if (op->value == 3) | 
 | 919 | 		 fprintf(output, "PLUS unary - -"); | 
 | 920 | 	     break; | 
 | 921 |         case XPATH_OP_MULT: | 
 | 922 | 	     if (op->value == 0) | 
 | 923 | 		 fprintf(output, "MULT *"); | 
 | 924 | 	     else if (op->value == 1) | 
 | 925 | 		 fprintf(output, "MULT div"); | 
 | 926 | 	     else | 
 | 927 | 		 fprintf(output, "MULT mod"); | 
 | 928 | 	     break; | 
 | 929 |         case XPATH_OP_UNION: | 
 | 930 | 	     fprintf(output, "UNION"); break; | 
 | 931 |         case XPATH_OP_ROOT: | 
 | 932 | 	     fprintf(output, "ROOT"); break; | 
 | 933 |         case XPATH_OP_NODE: | 
 | 934 | 	     fprintf(output, "NODE"); break; | 
 | 935 |         case XPATH_OP_RESET: | 
 | 936 | 	     fprintf(output, "RESET"); break; | 
 | 937 |         case XPATH_OP_SORT: | 
 | 938 | 	     fprintf(output, "SORT"); break; | 
 | 939 |         case XPATH_OP_COLLECT: { | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 940 | 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; | 
 | 941 | 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2; | 
 | 942 | 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 943 | 	    const xmlChar *prefix = op->value4; | 
 | 944 | 	    const xmlChar *name = op->value5; | 
 | 945 |  | 
 | 946 | 	    fprintf(output, "COLLECT "); | 
 | 947 | 	    switch (axis) { | 
 | 948 | 		case AXIS_ANCESTOR: | 
 | 949 | 		    fprintf(output, " 'ancestors' "); break; | 
 | 950 | 		case AXIS_ANCESTOR_OR_SELF: | 
 | 951 | 		    fprintf(output, " 'ancestors-or-self' "); break; | 
 | 952 | 		case AXIS_ATTRIBUTE: | 
 | 953 | 		    fprintf(output, " 'attributes' "); break; | 
 | 954 | 		case AXIS_CHILD: | 
 | 955 | 		    fprintf(output, " 'child' "); break; | 
 | 956 | 		case AXIS_DESCENDANT: | 
 | 957 | 		    fprintf(output, " 'descendant' "); break; | 
 | 958 | 		case AXIS_DESCENDANT_OR_SELF: | 
 | 959 | 		    fprintf(output, " 'descendant-or-self' "); break; | 
 | 960 | 		case AXIS_FOLLOWING: | 
 | 961 | 		    fprintf(output, " 'following' "); break; | 
 | 962 | 		case AXIS_FOLLOWING_SIBLING: | 
 | 963 | 		    fprintf(output, " 'following-siblings' "); break; | 
 | 964 | 		case AXIS_NAMESPACE: | 
 | 965 | 		    fprintf(output, " 'namespace' "); break; | 
 | 966 | 		case AXIS_PARENT: | 
 | 967 | 		    fprintf(output, " 'parent' "); break; | 
 | 968 | 		case AXIS_PRECEDING: | 
 | 969 | 		    fprintf(output, " 'preceding' "); break; | 
 | 970 | 		case AXIS_PRECEDING_SIBLING: | 
 | 971 | 		    fprintf(output, " 'preceding-sibling' "); break; | 
 | 972 | 		case AXIS_SELF: | 
 | 973 | 		    fprintf(output, " 'self' "); break; | 
 | 974 | 	    } | 
 | 975 | 	    switch (test) { | 
 | 976 |                 case NODE_TEST_NONE: | 
 | 977 | 		    fprintf(output, "'none' "); break; | 
 | 978 |                 case NODE_TEST_TYPE: | 
 | 979 | 		    fprintf(output, "'type' "); break; | 
 | 980 |                 case NODE_TEST_PI: | 
 | 981 | 		    fprintf(output, "'PI' "); break; | 
 | 982 |                 case NODE_TEST_ALL: | 
 | 983 | 		    fprintf(output, "'all' "); break; | 
 | 984 |                 case NODE_TEST_NS: | 
 | 985 | 		    fprintf(output, "'namespace' "); break; | 
 | 986 |                 case NODE_TEST_NAME: | 
 | 987 | 		    fprintf(output, "'name' "); break; | 
 | 988 | 	    } | 
 | 989 | 	    switch (type) { | 
 | 990 |                 case NODE_TYPE_NODE: | 
 | 991 | 		    fprintf(output, "'node' "); break; | 
 | 992 |                 case NODE_TYPE_COMMENT: | 
 | 993 | 		    fprintf(output, "'comment' "); break; | 
 | 994 |                 case NODE_TYPE_TEXT: | 
 | 995 | 		    fprintf(output, "'text' "); break; | 
 | 996 |                 case NODE_TYPE_PI: | 
 | 997 | 		    fprintf(output, "'PI' "); break; | 
 | 998 | 	    } | 
 | 999 | 	    if (prefix != NULL) | 
 | 1000 | 		fprintf(output, "%s:", prefix); | 
 | 1001 | 	    if (name != NULL) | 
| Daniel Veillard | 580ced8 | 2003-03-21 21:22:48 +0000 | [diff] [blame] | 1002 | 		fprintf(output, "%s", (const char *) name); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 1003 | 	    break; | 
 | 1004 |  | 
 | 1005 |         } | 
 | 1006 | 	case XPATH_OP_VALUE: { | 
 | 1007 | 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; | 
 | 1008 |  | 
 | 1009 | 	    fprintf(output, "ELEM "); | 
 | 1010 | 	    xmlXPathDebugDumpObject(output, object, 0); | 
 | 1011 | 	    goto finish; | 
 | 1012 | 	} | 
 | 1013 | 	case XPATH_OP_VARIABLE: { | 
 | 1014 | 	    const xmlChar *prefix = op->value5; | 
 | 1015 | 	    const xmlChar *name = op->value4; | 
 | 1016 |  | 
 | 1017 | 	    if (prefix != NULL) | 
 | 1018 | 		fprintf(output, "VARIABLE %s:%s", prefix, name); | 
 | 1019 | 	    else | 
 | 1020 | 		fprintf(output, "VARIABLE %s", name); | 
 | 1021 | 	    break; | 
 | 1022 | 	} | 
 | 1023 | 	case XPATH_OP_FUNCTION: { | 
 | 1024 | 	    int nbargs = op->value; | 
 | 1025 | 	    const xmlChar *prefix = op->value5; | 
 | 1026 | 	    const xmlChar *name = op->value4; | 
 | 1027 |  | 
 | 1028 | 	    if (prefix != NULL) | 
 | 1029 | 		fprintf(output, "FUNCTION %s:%s(%d args)", | 
 | 1030 | 			prefix, name, nbargs); | 
 | 1031 | 	    else | 
 | 1032 | 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs); | 
 | 1033 | 	    break; | 
 | 1034 | 	} | 
 | 1035 |         case XPATH_OP_ARG: fprintf(output, "ARG"); break; | 
 | 1036 |         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 1037 |         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 1038 | #ifdef LIBXML_XPTR_ENABLED | 
 | 1039 |         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; | 
 | 1040 | #endif | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 1041 | 	default: | 
 | 1042 |         fprintf(output, "UNKNOWN %d\n", op->op); return; | 
 | 1043 |     } | 
 | 1044 |     fprintf(output, "\n"); | 
 | 1045 | finish: | 
 | 1046 |     if (op->ch1 >= 0) | 
 | 1047 | 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); | 
 | 1048 |     if (op->ch2 >= 0) | 
 | 1049 | 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); | 
 | 1050 | } | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 1051 |  | 
| Daniel Veillard | 5e2dace | 2001-07-18 19:30:27 +0000 | [diff] [blame] | 1052 | /** | 
 | 1053 |  * xmlXPathDebugDumpCompExpr: | 
 | 1054 |  * @output:  the FILE * for the output | 
 | 1055 |  * @comp:  the precompiled XPath expression | 
 | 1056 |  * @depth:  the indentation level. | 
 | 1057 |  * | 
 | 1058 |  * Dumps the tree of the compiled XPath expression. | 
 | 1059 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 1060 | void | 
 | 1061 | xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, | 
 | 1062 | 	                  int depth) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 1063 |     int i; | 
 | 1064 |     char shift[100]; | 
 | 1065 |  | 
 | 1066 |     for (i = 0;((i < depth) && (i < 25));i++) | 
 | 1067 |         shift[2 * i] = shift[2 * i + 1] = ' '; | 
 | 1068 |     shift[2 * i] = shift[2 * i + 1] = 0; | 
 | 1069 |  | 
 | 1070 |     fprintf(output, shift); | 
 | 1071 |  | 
 | 1072 |     if (comp == NULL) { | 
 | 1073 | 	fprintf(output, "Compiled Expression is NULL\n"); | 
 | 1074 | 	return; | 
 | 1075 |     } | 
 | 1076 |     fprintf(output, "Compiled Expression : %d elements\n", | 
 | 1077 | 	    comp->nbStep); | 
 | 1078 |     i = comp->last; | 
 | 1079 |     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); | 
 | 1080 | } | 
| Daniel Veillard | 017b108 | 2001-06-21 11:20:21 +0000 | [diff] [blame] | 1081 | #endif /* LIBXML_DEBUG_ENABLED */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1082 |  | 
 | 1083 | /************************************************************************ | 
 | 1084 |  *									* | 
 | 1085 |  * 		Parser stacks related functions and macros		* | 
 | 1086 |  *									* | 
 | 1087 |  ************************************************************************/ | 
 | 1088 |  | 
| Daniel Veillard | 5e2dace | 2001-07-18 19:30:27 +0000 | [diff] [blame] | 1089 | /** | 
 | 1090 |  * valuePop: | 
 | 1091 |  * @ctxt: an XPath evaluation context | 
 | 1092 |  * | 
 | 1093 |  * Pops the top XPath object from the value stack | 
 | 1094 |  * | 
 | 1095 |  * Returns the XPath object just removed | 
 | 1096 |  */ | 
| Daniel Veillard | 1c732d2 | 2002-11-30 11:22:59 +0000 | [diff] [blame] | 1097 | extern xmlXPathObjectPtr | 
 | 1098 | valuePop(xmlXPathParserContextPtr ctxt) | 
 | 1099 | { | 
 | 1100 |     xmlXPathObjectPtr ret; | 
 | 1101 |  | 
 | 1102 |     if (ctxt->valueNr <= 0) | 
 | 1103 |         return (0); | 
 | 1104 |     ctxt->valueNr--; | 
 | 1105 |     if (ctxt->valueNr > 0) | 
 | 1106 |         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; | 
 | 1107 |     else | 
 | 1108 |         ctxt->value = NULL; | 
 | 1109 |     ret = ctxt->valueTab[ctxt->valueNr]; | 
 | 1110 |     ctxt->valueTab[ctxt->valueNr] = 0; | 
 | 1111 |     return (ret); | 
 | 1112 | } | 
| Daniel Veillard | 5e2dace | 2001-07-18 19:30:27 +0000 | [diff] [blame] | 1113 | /** | 
 | 1114 |  * valuePush: | 
 | 1115 |  * @ctxt:  an XPath evaluation context | 
 | 1116 |  * @value:  the XPath object | 
 | 1117 |  * | 
 | 1118 |  * Pushes a new XPath object on top of the value stack | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 1119 |  * | 
 | 1120 |  * returns the number of items on the value stack | 
| Daniel Veillard | 5e2dace | 2001-07-18 19:30:27 +0000 | [diff] [blame] | 1121 |  */ | 
| Daniel Veillard | 1c732d2 | 2002-11-30 11:22:59 +0000 | [diff] [blame] | 1122 | extern int | 
 | 1123 | valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) | 
 | 1124 | { | 
 | 1125 |     if (ctxt->valueNr >= ctxt->valueMax) { | 
| Daniel Veillard | a918b5b | 2004-09-26 14:25:37 +0000 | [diff] [blame] | 1126 |         xmlXPathObjectPtr *tmp; | 
 | 1127 |  | 
 | 1128 |         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, | 
 | 1129 |                                              2 * ctxt->valueMax * | 
| Daniel Veillard | 1c732d2 | 2002-11-30 11:22:59 +0000 | [diff] [blame] | 1130 |                                              sizeof(ctxt->valueTab[0])); | 
| Daniel Veillard | a918b5b | 2004-09-26 14:25:37 +0000 | [diff] [blame] | 1131 |         if (tmp == NULL) { | 
| Daniel Veillard | 1c732d2 | 2002-11-30 11:22:59 +0000 | [diff] [blame] | 1132 |             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); | 
 | 1133 |             return (0); | 
 | 1134 |         } | 
| Daniel Veillard | a918b5b | 2004-09-26 14:25:37 +0000 | [diff] [blame] | 1135 |         ctxt->valueMax *= 2; | 
 | 1136 | 	ctxt->valueTab = tmp; | 
| Daniel Veillard | 1c732d2 | 2002-11-30 11:22:59 +0000 | [diff] [blame] | 1137 |     } | 
 | 1138 |     ctxt->valueTab[ctxt->valueNr] = value; | 
 | 1139 |     ctxt->value = value; | 
 | 1140 |     return (ctxt->valueNr++); | 
 | 1141 | } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1142 |  | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1143 | /** | 
 | 1144 |  * xmlXPathPopBoolean: | 
 | 1145 |  * @ctxt:  an XPath parser context | 
 | 1146 |  * | 
 | 1147 |  * Pops a boolean from the stack, handling conversion if needed. | 
 | 1148 |  * Check error with #xmlXPathCheckError. | 
 | 1149 |  * | 
 | 1150 |  * Returns the boolean | 
 | 1151 |  */ | 
 | 1152 | int | 
 | 1153 | xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { | 
 | 1154 |     xmlXPathObjectPtr obj; | 
 | 1155 |     int ret; | 
 | 1156 |  | 
 | 1157 |     obj = valuePop(ctxt); | 
 | 1158 |     if (obj == NULL) { | 
 | 1159 | 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); | 
 | 1160 | 	return(0); | 
 | 1161 |     } | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1162 |     if (obj->type != XPATH_BOOLEAN) | 
 | 1163 | 	ret = xmlXPathCastToBoolean(obj); | 
 | 1164 |     else | 
 | 1165 |         ret = obj->boolval; | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1166 |     xmlXPathFreeObject(obj); | 
 | 1167 |     return(ret); | 
 | 1168 | } | 
 | 1169 |  | 
 | 1170 | /** | 
 | 1171 |  * xmlXPathPopNumber: | 
 | 1172 |  * @ctxt:  an XPath parser context | 
 | 1173 |  * | 
 | 1174 |  * Pops a number from the stack, handling conversion if needed. | 
 | 1175 |  * Check error with #xmlXPathCheckError. | 
 | 1176 |  * | 
 | 1177 |  * Returns the number | 
 | 1178 |  */ | 
 | 1179 | double | 
 | 1180 | xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { | 
 | 1181 |     xmlXPathObjectPtr obj; | 
 | 1182 |     double ret; | 
 | 1183 |  | 
 | 1184 |     obj = valuePop(ctxt); | 
 | 1185 |     if (obj == NULL) { | 
 | 1186 | 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); | 
 | 1187 | 	return(0); | 
 | 1188 |     } | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1189 |     if (obj->type != XPATH_NUMBER) | 
 | 1190 | 	ret = xmlXPathCastToNumber(obj); | 
 | 1191 |     else | 
 | 1192 |         ret = obj->floatval; | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1193 |     xmlXPathFreeObject(obj); | 
 | 1194 |     return(ret); | 
 | 1195 | } | 
 | 1196 |  | 
 | 1197 | /** | 
 | 1198 |  * xmlXPathPopString: | 
 | 1199 |  * @ctxt:  an XPath parser context | 
 | 1200 |  * | 
 | 1201 |  * Pops a string from the stack, handling conversion if needed. | 
 | 1202 |  * Check error with #xmlXPathCheckError. | 
 | 1203 |  * | 
 | 1204 |  * Returns the string | 
 | 1205 |  */ | 
 | 1206 | xmlChar * | 
 | 1207 | xmlXPathPopString (xmlXPathParserContextPtr ctxt) { | 
 | 1208 |     xmlXPathObjectPtr obj; | 
 | 1209 |     xmlChar * ret; | 
 | 1210 |  | 
 | 1211 |     obj = valuePop(ctxt); | 
 | 1212 |     if (obj == NULL) { | 
 | 1213 | 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); | 
 | 1214 | 	return(NULL); | 
 | 1215 |     } | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1216 |     ret = xmlXPathCastToString(obj);	/* this does required strdup */ | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1217 |     /* TODO: needs refactoring somewhere else */ | 
 | 1218 |     if (obj->stringval == ret) | 
 | 1219 | 	obj->stringval = NULL; | 
 | 1220 |     xmlXPathFreeObject(obj); | 
 | 1221 |     return(ret); | 
 | 1222 | } | 
 | 1223 |  | 
 | 1224 | /** | 
 | 1225 |  * xmlXPathPopNodeSet: | 
 | 1226 |  * @ctxt:  an XPath parser context | 
 | 1227 |  * | 
 | 1228 |  * Pops a node-set from the stack, handling conversion if needed. | 
 | 1229 |  * Check error with #xmlXPathCheckError. | 
 | 1230 |  * | 
 | 1231 |  * Returns the node-set | 
 | 1232 |  */ | 
 | 1233 | xmlNodeSetPtr | 
 | 1234 | xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { | 
 | 1235 |     xmlXPathObjectPtr obj; | 
 | 1236 |     xmlNodeSetPtr ret; | 
 | 1237 |  | 
 | 1238 |     if (ctxt->value == NULL) { | 
 | 1239 | 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); | 
 | 1240 | 	return(NULL); | 
 | 1241 |     } | 
 | 1242 |     if (!xmlXPathStackIsNodeSet(ctxt)) { | 
 | 1243 | 	xmlXPathSetTypeError(ctxt); | 
 | 1244 | 	return(NULL); | 
 | 1245 |     } | 
 | 1246 |     obj = valuePop(ctxt); | 
 | 1247 |     ret = obj->nodesetval; | 
| William M. Brack | e9449c5 | 2004-07-11 14:41:20 +0000 | [diff] [blame] | 1248 | #if 0 | 
| Daniel Veillard | 9deb242 | 2003-07-28 20:40:59 +0000 | [diff] [blame] | 1249 |     /* to fix memory leak of not clearing obj->user */ | 
 | 1250 |     if (obj->boolval && obj->user != NULL) | 
 | 1251 |         xmlFreeNodeList((xmlNodePtr) obj->user); | 
| William M. Brack | e9449c5 | 2004-07-11 14:41:20 +0000 | [diff] [blame] | 1252 | #endif | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1253 |     xmlXPathFreeNodeSetList(obj); | 
 | 1254 |     return(ret); | 
 | 1255 | } | 
 | 1256 |  | 
 | 1257 | /** | 
 | 1258 |  * xmlXPathPopExternal: | 
 | 1259 |  * @ctxt:  an XPath parser context | 
 | 1260 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 1261 |  * Pops an external object from the stack, handling conversion if needed. | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1262 |  * Check error with #xmlXPathCheckError. | 
 | 1263 |  * | 
 | 1264 |  * Returns the object | 
 | 1265 |  */ | 
 | 1266 | void * | 
 | 1267 | xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { | 
 | 1268 |     xmlXPathObjectPtr obj; | 
 | 1269 |     void * ret; | 
 | 1270 |  | 
 | 1271 |     if (ctxt->value == NULL) { | 
 | 1272 | 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); | 
 | 1273 | 	return(NULL); | 
 | 1274 |     } | 
 | 1275 |     if (ctxt->value->type != XPATH_USERS) { | 
 | 1276 | 	xmlXPathSetTypeError(ctxt); | 
 | 1277 | 	return(NULL); | 
 | 1278 |     } | 
 | 1279 |     obj = valuePop(ctxt); | 
 | 1280 |     ret = obj->user; | 
 | 1281 |     xmlXPathFreeObject(obj); | 
 | 1282 |     return(ret); | 
 | 1283 | } | 
 | 1284 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1285 | /* | 
 | 1286 |  * Macros for accessing the content. Those should be used only by the parser, | 
 | 1287 |  * and not exported. | 
 | 1288 |  * | 
 | 1289 |  * Dirty macros, i.e. one need to make assumption on the context to use them | 
 | 1290 |  * | 
 | 1291 |  *   CUR_PTR return the current pointer to the xmlChar to be parsed. | 
 | 1292 |  *   CUR     returns the current xmlChar value, i.e. a 8 bit value | 
 | 1293 |  *           in ISO-Latin or UTF-8. | 
 | 1294 |  *           This should be used internally by the parser | 
 | 1295 |  *           only to compare to ASCII values otherwise it would break when | 
 | 1296 |  *           running with UTF-8 encoding. | 
 | 1297 |  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only | 
 | 1298 |  *           to compare on ASCII based substring. | 
 | 1299 |  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined | 
 | 1300 |  *           strings within the parser. | 
 | 1301 |  *   CURRENT Returns the current char value, with the full decoding of | 
 | 1302 |  *           UTF-8 if we are using this mode. It returns an int. | 
 | 1303 |  *   NEXT    Skip to the next character, this does the proper decoding | 
 | 1304 |  *           in UTF-8 mode. It also pop-up unfinished entities on the fly. | 
 | 1305 |  *           It returns the pointer to the current xmlChar. | 
 | 1306 |  */ | 
 | 1307 |  | 
 | 1308 | #define CUR (*ctxt->cur) | 
 | 1309 | #define SKIP(val) ctxt->cur += (val) | 
 | 1310 | #define NXT(val) ctxt->cur[(val)] | 
 | 1311 | #define CUR_PTR ctxt->cur | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 1312 | #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) | 
 | 1313 |  | 
 | 1314 | #define COPY_BUF(l,b,i,v)                                              \ | 
 | 1315 |     if (l == 1) b[i++] = (xmlChar) v;                                  \ | 
 | 1316 |     else i += xmlCopyChar(l,&b[i],v) | 
 | 1317 |  | 
 | 1318 | #define NEXTL(l)  ctxt->cur += l | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1319 |  | 
 | 1320 | #define SKIP_BLANKS 							\ | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 1321 |     while (IS_BLANK_CH(*(ctxt->cur))) NEXT | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1322 |  | 
 | 1323 | #define CURRENT (*ctxt->cur) | 
 | 1324 | #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur) | 
 | 1325 |  | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1326 |  | 
 | 1327 | #ifndef DBL_DIG | 
 | 1328 | #define DBL_DIG 16 | 
 | 1329 | #endif | 
 | 1330 | #ifndef DBL_EPSILON | 
 | 1331 | #define DBL_EPSILON 1E-9 | 
 | 1332 | #endif | 
 | 1333 |  | 
 | 1334 | #define UPPER_DOUBLE 1E9 | 
 | 1335 | #define LOWER_DOUBLE 1E-5 | 
 | 1336 |  | 
 | 1337 | #define INTEGER_DIGITS DBL_DIG | 
 | 1338 | #define FRACTION_DIGITS (DBL_DIG + 1) | 
 | 1339 | #define EXPONENT_DIGITS (3 + 2) | 
 | 1340 |  | 
 | 1341 | /** | 
 | 1342 |  * xmlXPathFormatNumber: | 
 | 1343 |  * @number:     number to format | 
 | 1344 |  * @buffer:     output buffer | 
 | 1345 |  * @buffersize: size of output buffer | 
 | 1346 |  * | 
 | 1347 |  * Convert the number into a string representation. | 
 | 1348 |  */ | 
 | 1349 | static void | 
 | 1350 | xmlXPathFormatNumber(double number, char buffer[], int buffersize) | 
 | 1351 | { | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 1352 |     switch (xmlXPathIsInf(number)) { | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1353 |     case 1: | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 1354 | 	if (buffersize > (int)sizeof("Infinity")) | 
| Aleksey Sanin | 49cc975 | 2002-06-14 17:07:10 +0000 | [diff] [blame] | 1355 | 	    snprintf(buffer, buffersize, "Infinity"); | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1356 | 	break; | 
 | 1357 |     case -1: | 
 | 1358 | 	if (buffersize > (int)sizeof("-Infinity")) | 
| Aleksey Sanin | 49cc975 | 2002-06-14 17:07:10 +0000 | [diff] [blame] | 1359 | 	    snprintf(buffer, buffersize, "-Infinity"); | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1360 | 	break; | 
 | 1361 |     default: | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 1362 | 	if (xmlXPathIsNaN(number)) { | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1363 | 	    if (buffersize > (int)sizeof("NaN")) | 
| Aleksey Sanin | 49cc975 | 2002-06-14 17:07:10 +0000 | [diff] [blame] | 1364 | 		snprintf(buffer, buffersize, "NaN"); | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 1365 | 	} else if (number == 0 && xmlXPathGetSign(number) != 0) { | 
| Aleksey Sanin | 49cc975 | 2002-06-14 17:07:10 +0000 | [diff] [blame] | 1366 | 	    snprintf(buffer, buffersize, "0"); | 
| Daniel Veillard | 28cac6b | 2002-03-19 11:25:30 +0000 | [diff] [blame] | 1367 | 	} else if (number == ((int) number)) { | 
 | 1368 | 	    char work[30]; | 
 | 1369 | 	    char *ptr, *cur; | 
 | 1370 | 	    int res, value = (int) number; | 
 | 1371 |  | 
 | 1372 |             ptr = &buffer[0]; | 
 | 1373 | 	    if (value < 0) { | 
 | 1374 | 		*ptr++ = '-'; | 
 | 1375 | 		value = -value; | 
 | 1376 | 	    } | 
 | 1377 | 	    if (value == 0) { | 
 | 1378 | 		*ptr++ = '0'; | 
 | 1379 | 	    } else { | 
 | 1380 | 		cur = &work[0]; | 
 | 1381 | 		while (value != 0) { | 
 | 1382 | 		    res = value % 10; | 
 | 1383 | 		    value = value / 10; | 
 | 1384 | 		    *cur++ = '0' + res; | 
 | 1385 | 		} | 
 | 1386 | 		cur--; | 
 | 1387 | 		while ((cur >= &work[0]) && (ptr - buffer < buffersize)) { | 
 | 1388 | 		    *ptr++ = *cur--; | 
 | 1389 | 		} | 
 | 1390 | 	    } | 
 | 1391 | 	    if (ptr - buffer < buffersize) { | 
 | 1392 | 		*ptr = 0; | 
 | 1393 | 	    } else if (buffersize > 0) { | 
 | 1394 | 		ptr--; | 
 | 1395 | 		*ptr = 0; | 
 | 1396 | 	    } | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1397 | 	} else { | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 1398 | 	    /* 3 is sign, decimal point, and terminating zero */ | 
 | 1399 | 	    char work[DBL_DIG + EXPONENT_DIGITS + 3]; | 
 | 1400 | 	    int integer_place, fraction_place; | 
 | 1401 | 	    char *ptr; | 
 | 1402 | 	    char *after_fraction; | 
 | 1403 | 	    double absolute_value; | 
 | 1404 | 	    int size; | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1405 |  | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 1406 | 	    absolute_value = fabs(number); | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1407 |  | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 1408 | 	    /* | 
 | 1409 | 	     * First choose format - scientific or regular floating point. | 
 | 1410 | 	     * In either case, result is in work, and after_fraction points | 
 | 1411 | 	     * just past the fractional part. | 
 | 1412 | 	    */ | 
 | 1413 | 	    if ( ((absolute_value > UPPER_DOUBLE) || | 
 | 1414 | 		  (absolute_value < LOWER_DOUBLE)) && | 
 | 1415 | 		 (absolute_value != 0.0) ) { | 
 | 1416 | 		/* Use scientific notation */ | 
 | 1417 | 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1; | 
 | 1418 | 		fraction_place = DBL_DIG - 1; | 
 | 1419 | 		snprintf(work, sizeof(work),"%*.*e", | 
 | 1420 | 			 integer_place, fraction_place, number); | 
 | 1421 | 		after_fraction = strchr(work + DBL_DIG, 'e'); | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1422 | 	    } | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 1423 | 	    else { | 
 | 1424 | 		/* Use regular notation */ | 
| Daniel Veillard | 56f0646 | 2001-06-24 21:34:03 +0000 | [diff] [blame] | 1425 | 		if (absolute_value > 0.0) | 
 | 1426 | 		    integer_place = 1 + (int)log10(absolute_value); | 
 | 1427 | 		else | 
| Daniel Veillard | a3067d1 | 2001-06-24 21:39:39 +0000 | [diff] [blame] | 1428 | 		    integer_place = 0; | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 1429 | 		fraction_place = (integer_place > 0) | 
 | 1430 | 		    ? DBL_DIG - integer_place | 
 | 1431 | 		    : DBL_DIG; | 
 | 1432 | 		size = snprintf(work, sizeof(work), "%0.*f", | 
 | 1433 | 				fraction_place, number); | 
 | 1434 | 		after_fraction = work + size; | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1435 | 	    } | 
 | 1436 |  | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 1437 | 	    /* Remove fractional trailing zeroes */ | 
 | 1438 | 	    ptr = after_fraction; | 
 | 1439 | 	    while (*(--ptr) == '0') | 
 | 1440 | 		; | 
 | 1441 | 	    if (*ptr != '.') | 
 | 1442 | 	        ptr++; | 
| Daniel Veillard | 5dd3c96 | 2003-09-12 15:32:16 +0000 | [diff] [blame] | 1443 | 	    while ((*ptr++ = *after_fraction++) != 0); | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 1444 |  | 
 | 1445 | 	    /* Finally copy result back to caller */ | 
 | 1446 | 	    size = strlen(work) + 1; | 
 | 1447 | 	    if (size > buffersize) { | 
 | 1448 | 		work[buffersize - 1] = 0; | 
 | 1449 | 		size = buffersize; | 
 | 1450 | 	    } | 
| Daniel Veillard | 5dd3c96 | 2003-09-12 15:32:16 +0000 | [diff] [blame] | 1451 | 	    memmove(buffer, work, size); | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1452 | 	} | 
 | 1453 | 	break; | 
 | 1454 |     } | 
 | 1455 | } | 
 | 1456 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1457 |  | 
 | 1458 | /************************************************************************ | 
 | 1459 |  *									* | 
 | 1460 |  *			Routines to handle NodeSets			* | 
 | 1461 |  *									* | 
 | 1462 |  ************************************************************************/ | 
 | 1463 |  | 
 | 1464 | /** | 
| Daniel Veillard | e4fa293 | 2003-03-26 00:38:10 +0000 | [diff] [blame] | 1465 |  * xmlXPathOrderDocElems: | 
 | 1466 |  * @doc:  an input document | 
 | 1467 |  * | 
 | 1468 |  * Call this routine to speed up XPath computation on static documents. | 
 | 1469 |  * This stamps all the element nodes with the document order | 
 | 1470 |  * Like for line information, the order is kept in the element->content | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1471 |  * field, the value stored is actually - the node number (starting at -1) | 
 | 1472 |  * to be able to differentiate from line numbers. | 
| Daniel Veillard | e4fa293 | 2003-03-26 00:38:10 +0000 | [diff] [blame] | 1473 |  * | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1474 |  * Returns the number of elements found in the document or -1 in case | 
| Daniel Veillard | e4fa293 | 2003-03-26 00:38:10 +0000 | [diff] [blame] | 1475 |  *    of error. | 
 | 1476 |  */ | 
 | 1477 | long | 
 | 1478 | xmlXPathOrderDocElems(xmlDocPtr doc) { | 
 | 1479 |     long count = 0; | 
 | 1480 |     xmlNodePtr cur; | 
 | 1481 |  | 
 | 1482 |     if (doc == NULL) | 
 | 1483 | 	return(-1); | 
 | 1484 |     cur = doc->children; | 
 | 1485 |     while (cur != NULL) { | 
 | 1486 | 	if (cur->type == XML_ELEMENT_NODE) { | 
 | 1487 | 	    cur->content = (void *) (-(++count)); | 
 | 1488 | 	    if (cur->children != NULL) { | 
 | 1489 | 		cur = cur->children; | 
 | 1490 | 		continue; | 
 | 1491 | 	    } | 
 | 1492 | 	} | 
 | 1493 | 	if (cur->next != NULL) { | 
 | 1494 | 	    cur = cur->next; | 
 | 1495 | 	    continue; | 
 | 1496 | 	} | 
 | 1497 | 	do { | 
 | 1498 | 	    cur = cur->parent; | 
 | 1499 | 	    if (cur == NULL) | 
 | 1500 | 		break; | 
 | 1501 | 	    if (cur == (xmlNodePtr) doc) { | 
 | 1502 | 		cur = NULL; | 
 | 1503 | 		break; | 
 | 1504 | 	    } | 
 | 1505 | 	    if (cur->next != NULL) { | 
 | 1506 | 		cur = cur->next; | 
 | 1507 | 		break; | 
 | 1508 | 	    } | 
 | 1509 | 	} while (cur != NULL); | 
 | 1510 |     } | 
 | 1511 |     return(count); | 
 | 1512 | } | 
 | 1513 |  | 
 | 1514 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1515 |  * xmlXPathCmpNodes: | 
 | 1516 |  * @node1:  the first node | 
 | 1517 |  * @node2:  the second node | 
 | 1518 |  * | 
 | 1519 |  * Compare two nodes w.r.t document order | 
 | 1520 |  * | 
 | 1521 |  * Returns -2 in case of error 1 if first point < second point, 0 if | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1522 |  *         it's the same node, -1 otherwise | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1523 |  */ | 
 | 1524 | int | 
 | 1525 | xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { | 
 | 1526 |     int depth1, depth2; | 
| Daniel Veillard | edfd588 | 2003-03-07 14:20:40 +0000 | [diff] [blame] | 1527 |     int attr1 = 0, attr2 = 0; | 
| William M. Brack | e8d1bd9 | 2003-12-23 01:28:58 +0000 | [diff] [blame] | 1528 |     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1529 |     xmlNodePtr cur, root; | 
 | 1530 |  | 
 | 1531 |     if ((node1 == NULL) || (node2 == NULL)) | 
 | 1532 | 	return(-2); | 
 | 1533 |     /* | 
 | 1534 |      * a couple of optimizations which will avoid computations in most cases | 
 | 1535 |      */ | 
| Daniel Veillard | edfd588 | 2003-03-07 14:20:40 +0000 | [diff] [blame] | 1536 |     if (node1->type == XML_ATTRIBUTE_NODE) { | 
 | 1537 | 	attr1 = 1; | 
| William M. Brack | e8d1bd9 | 2003-12-23 01:28:58 +0000 | [diff] [blame] | 1538 | 	attrNode1 = node1; | 
| Daniel Veillard | edfd588 | 2003-03-07 14:20:40 +0000 | [diff] [blame] | 1539 | 	node1 = node1->parent; | 
 | 1540 |     } | 
 | 1541 |     if (node2->type == XML_ATTRIBUTE_NODE) { | 
 | 1542 | 	attr2 = 1; | 
| William M. Brack | e8d1bd9 | 2003-12-23 01:28:58 +0000 | [diff] [blame] | 1543 | 	attrNode2 = node2; | 
| Daniel Veillard | edfd588 | 2003-03-07 14:20:40 +0000 | [diff] [blame] | 1544 | 	node2 = node2->parent; | 
 | 1545 |     } | 
 | 1546 |     if (node1 == node2) { | 
| William M. Brack | e8d1bd9 | 2003-12-23 01:28:58 +0000 | [diff] [blame] | 1547 | 	if (attr1 == attr2) { | 
 | 1548 | 	    /* not required, but we keep attributes in order */ | 
 | 1549 | 	    if (attr1 != 0) { | 
 | 1550 | 	        cur = attrNode2->prev; | 
 | 1551 | 		while (cur != NULL) { | 
 | 1552 | 		    if (cur == attrNode1) | 
 | 1553 | 		        return (1); | 
 | 1554 | 		    cur = cur->prev; | 
 | 1555 | 		} | 
 | 1556 | 		return (-1); | 
 | 1557 | 	    } | 
| Daniel Veillard | edfd588 | 2003-03-07 14:20:40 +0000 | [diff] [blame] | 1558 | 	    return(0); | 
| William M. Brack | e8d1bd9 | 2003-12-23 01:28:58 +0000 | [diff] [blame] | 1559 | 	} | 
| Daniel Veillard | edfd588 | 2003-03-07 14:20:40 +0000 | [diff] [blame] | 1560 | 	if (attr2 == 1) | 
 | 1561 | 	    return(1); | 
 | 1562 | 	return(-1); | 
 | 1563 |     } | 
| Daniel Veillard | b33c201 | 2001-04-25 12:59:04 +0000 | [diff] [blame] | 1564 |     if ((node1->type == XML_NAMESPACE_DECL) || | 
 | 1565 |         (node2->type == XML_NAMESPACE_DECL)) | 
 | 1566 | 	return(1); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1567 |     if (node1 == node2->prev) | 
 | 1568 | 	return(1); | 
 | 1569 |     if (node1 == node2->next) | 
 | 1570 | 	return(-1); | 
 | 1571 |  | 
 | 1572 |     /* | 
| Daniel Veillard | e4fa293 | 2003-03-26 00:38:10 +0000 | [diff] [blame] | 1573 |      * Speedup using document order if availble. | 
| Daniel Veillard | 7216cfd | 2002-11-08 15:10:00 +0000 | [diff] [blame] | 1574 |      */ | 
 | 1575 |     if ((node1->type == XML_ELEMENT_NODE) && | 
 | 1576 | 	(node2->type == XML_ELEMENT_NODE) && | 
| Daniel Veillard | e4fa293 | 2003-03-26 00:38:10 +0000 | [diff] [blame] | 1577 | 	(0 > (long) node1->content) && | 
 | 1578 | 	(0 > (long) node2->content) && | 
 | 1579 | 	(node1->doc == node2->doc)) { | 
 | 1580 | 	long l1, l2; | 
 | 1581 |  | 
 | 1582 | 	l1 = -((long) node1->content); | 
 | 1583 | 	l2 = -((long) node2->content); | 
| Daniel Veillard | 7216cfd | 2002-11-08 15:10:00 +0000 | [diff] [blame] | 1584 | 	if (l1 < l2) | 
 | 1585 | 	    return(1); | 
 | 1586 | 	if (l1 > l2) | 
 | 1587 | 	    return(-1); | 
 | 1588 |     } | 
| Daniel Veillard | e4fa293 | 2003-03-26 00:38:10 +0000 | [diff] [blame] | 1589 |  | 
| Daniel Veillard | 7216cfd | 2002-11-08 15:10:00 +0000 | [diff] [blame] | 1590 |     /* | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1591 |      * compute depth to root | 
 | 1592 |      */ | 
 | 1593 |     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { | 
 | 1594 | 	if (cur == node1) | 
 | 1595 | 	    return(1); | 
 | 1596 | 	depth2++; | 
 | 1597 |     } | 
 | 1598 |     root = cur; | 
 | 1599 |     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { | 
 | 1600 | 	if (cur == node2) | 
 | 1601 | 	    return(-1); | 
 | 1602 | 	depth1++; | 
 | 1603 |     } | 
 | 1604 |     /* | 
 | 1605 |      * Distinct document (or distinct entities :-( ) case. | 
 | 1606 |      */ | 
 | 1607 |     if (root != cur) { | 
 | 1608 | 	return(-2); | 
 | 1609 |     } | 
 | 1610 |     /* | 
 | 1611 |      * get the nearest common ancestor. | 
 | 1612 |      */ | 
 | 1613 |     while (depth1 > depth2) { | 
 | 1614 | 	depth1--; | 
 | 1615 | 	node1 = node1->parent; | 
 | 1616 |     } | 
 | 1617 |     while (depth2 > depth1) { | 
 | 1618 | 	depth2--; | 
 | 1619 | 	node2 = node2->parent; | 
 | 1620 |     } | 
 | 1621 |     while (node1->parent != node2->parent) { | 
 | 1622 | 	node1 = node1->parent; | 
 | 1623 | 	node2 = node2->parent; | 
 | 1624 | 	/* should not happen but just in case ... */ | 
 | 1625 | 	if ((node1 == NULL) || (node2 == NULL)) | 
 | 1626 | 	    return(-2); | 
 | 1627 |     } | 
 | 1628 |     /* | 
 | 1629 |      * Find who's first. | 
 | 1630 |      */ | 
| Daniel Veillard | f49be47 | 2004-02-17 11:48:18 +0000 | [diff] [blame] | 1631 |     if (node1 == node2->prev) | 
 | 1632 | 	return(1); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1633 |     if (node1 == node2->next) | 
 | 1634 | 	return(-1); | 
| Daniel Veillard | f49be47 | 2004-02-17 11:48:18 +0000 | [diff] [blame] | 1635 |     /* | 
 | 1636 |      * Speedup using document order if availble. | 
 | 1637 |      */ | 
 | 1638 |     if ((node1->type == XML_ELEMENT_NODE) && | 
 | 1639 | 	(node2->type == XML_ELEMENT_NODE) && | 
 | 1640 | 	(0 > (long) node1->content) && | 
 | 1641 | 	(0 > (long) node2->content) && | 
 | 1642 | 	(node1->doc == node2->doc)) { | 
 | 1643 | 	long l1, l2; | 
 | 1644 |  | 
 | 1645 | 	l1 = -((long) node1->content); | 
 | 1646 | 	l2 = -((long) node2->content); | 
 | 1647 | 	if (l1 < l2) | 
 | 1648 | 	    return(1); | 
 | 1649 | 	if (l1 > l2) | 
 | 1650 | 	    return(-1); | 
 | 1651 |     } | 
 | 1652 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1653 |     for (cur = node1->next;cur != NULL;cur = cur->next) | 
 | 1654 | 	if (cur == node2) | 
 | 1655 | 	    return(1); | 
 | 1656 |     return(-1); /* assume there is no sibling list corruption */ | 
 | 1657 | } | 
 | 1658 |  | 
 | 1659 | /** | 
 | 1660 |  * xmlXPathNodeSetSort: | 
 | 1661 |  * @set:  the node set | 
 | 1662 |  * | 
 | 1663 |  * Sort the node set in document order | 
 | 1664 |  */ | 
 | 1665 | void | 
 | 1666 | xmlXPathNodeSetSort(xmlNodeSetPtr set) { | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1667 |     int i, j, incr, len; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1668 |     xmlNodePtr tmp; | 
 | 1669 |  | 
 | 1670 |     if (set == NULL) | 
 | 1671 | 	return; | 
 | 1672 |  | 
 | 1673 |     /* Use Shell's sort to sort the node-set */ | 
 | 1674 |     len = set->nodeNr; | 
 | 1675 |     for (incr = len / 2; incr > 0; incr /= 2) { | 
 | 1676 | 	for (i = incr; i < len; i++) { | 
 | 1677 | 	    j = i - incr; | 
 | 1678 | 	    while (j >= 0) { | 
| Bjorn Reese | e1dc011 | 2001-03-03 12:09:03 +0000 | [diff] [blame] | 1679 | 		if (xmlXPathCmpNodes(set->nodeTab[j], | 
 | 1680 | 				     set->nodeTab[j + incr]) == -1) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1681 | 		    tmp = set->nodeTab[j]; | 
 | 1682 | 		    set->nodeTab[j] = set->nodeTab[j + incr]; | 
 | 1683 | 		    set->nodeTab[j + incr] = tmp; | 
 | 1684 | 		    j -= incr; | 
 | 1685 | 		} else | 
 | 1686 | 		    break; | 
 | 1687 | 	    } | 
 | 1688 | 	} | 
 | 1689 |     } | 
 | 1690 | } | 
 | 1691 |  | 
 | 1692 | #define XML_NODESET_DEFAULT	10 | 
 | 1693 | /** | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1694 |  * xmlXPathNodeSetDupNs: | 
 | 1695 |  * @node:  the parent node of the namespace XPath node | 
 | 1696 |  * @ns:  the libxml namespace declaration node. | 
 | 1697 |  * | 
 | 1698 |  * Namespace node in libxml don't match the XPath semantic. In a node set | 
 | 1699 |  * the namespace nodes are duplicated and the next pointer is set to the | 
 | 1700 |  * parent node in the XPath semantic. | 
 | 1701 |  * | 
 | 1702 |  * Returns the newly created object. | 
 | 1703 |  */ | 
 | 1704 | static xmlNodePtr | 
 | 1705 | xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { | 
 | 1706 |     xmlNsPtr cur; | 
 | 1707 |  | 
 | 1708 |     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) | 
 | 1709 | 	return(NULL); | 
 | 1710 |     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) | 
 | 1711 | 	return((xmlNodePtr) ns); | 
 | 1712 |  | 
 | 1713 |     /* | 
 | 1714 |      * Allocate a new Namespace and fill the fields. | 
 | 1715 |      */ | 
 | 1716 |     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); | 
 | 1717 |     if (cur == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1718 |         xmlXPathErrMemory(NULL, "duplicating namespace\n"); | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1719 | 	return(NULL); | 
 | 1720 |     } | 
 | 1721 |     memset(cur, 0, sizeof(xmlNs)); | 
 | 1722 |     cur->type = XML_NAMESPACE_DECL; | 
 | 1723 |     if (ns->href != NULL) | 
 | 1724 | 	cur->href = xmlStrdup(ns->href);  | 
 | 1725 |     if (ns->prefix != NULL) | 
 | 1726 | 	cur->prefix = xmlStrdup(ns->prefix);  | 
 | 1727 |     cur->next = (xmlNsPtr) node; | 
 | 1728 |     return((xmlNodePtr) cur); | 
 | 1729 | } | 
 | 1730 |  | 
 | 1731 | /** | 
 | 1732 |  * xmlXPathNodeSetFreeNs: | 
 | 1733 |  * @ns:  the XPath namespace node found in a nodeset. | 
 | 1734 |  * | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1735 |  * Namespace nodes in libxml don't match the XPath semantic. In a node set | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1736 |  * the namespace nodes are duplicated and the next pointer is set to the | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1737 |  * parent node in the XPath semantic. Check if such a node needs to be freed | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1738 |  */ | 
| Aleksey Sanin | f8cb6dd | 2002-06-04 04:27:06 +0000 | [diff] [blame] | 1739 | void | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1740 | xmlXPathNodeSetFreeNs(xmlNsPtr ns) { | 
 | 1741 |     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) | 
 | 1742 | 	return; | 
 | 1743 |  | 
 | 1744 |     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { | 
 | 1745 | 	if (ns->href != NULL) | 
 | 1746 | 	    xmlFree((xmlChar *)ns->href); | 
 | 1747 | 	if (ns->prefix != NULL) | 
 | 1748 | 	    xmlFree((xmlChar *)ns->prefix); | 
 | 1749 | 	xmlFree(ns); | 
 | 1750 |     } | 
 | 1751 | } | 
 | 1752 |  | 
 | 1753 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1754 |  * xmlXPathNodeSetCreate: | 
 | 1755 |  * @val:  an initial xmlNodePtr, or NULL | 
 | 1756 |  * | 
 | 1757 |  * Create a new xmlNodeSetPtr of type double and of value @val | 
 | 1758 |  * | 
 | 1759 |  * Returns the newly created object. | 
 | 1760 |  */ | 
 | 1761 | xmlNodeSetPtr | 
 | 1762 | xmlXPathNodeSetCreate(xmlNodePtr val) { | 
 | 1763 |     xmlNodeSetPtr ret; | 
 | 1764 |  | 
 | 1765 |     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); | 
 | 1766 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1767 |         xmlXPathErrMemory(NULL, "creating nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1768 | 	return(NULL); | 
 | 1769 |     } | 
 | 1770 |     memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); | 
 | 1771 |     if (val != NULL) { | 
 | 1772 |         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * | 
 | 1773 | 					     sizeof(xmlNodePtr)); | 
 | 1774 | 	if (ret->nodeTab == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1775 | 	    xmlXPathErrMemory(NULL, "creating nodeset\n"); | 
 | 1776 | 	    xmlFree(ret); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1777 | 	    return(NULL); | 
 | 1778 | 	} | 
 | 1779 | 	memset(ret->nodeTab, 0 , | 
 | 1780 | 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); | 
 | 1781 |         ret->nodeMax = XML_NODESET_DEFAULT; | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1782 | 	if (val->type == XML_NAMESPACE_DECL) { | 
 | 1783 | 	    xmlNsPtr ns = (xmlNsPtr) val; | 
 | 1784 |  | 
 | 1785 | 	    ret->nodeTab[ret->nodeNr++] = | 
 | 1786 | 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); | 
 | 1787 | 	} else | 
 | 1788 | 	    ret->nodeTab[ret->nodeNr++] = val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1789 |     } | 
 | 1790 |     return(ret); | 
 | 1791 | } | 
 | 1792 |  | 
 | 1793 | /** | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1794 |  * xmlXPathNodeSetContains: | 
 | 1795 |  * @cur:  the node-set | 
 | 1796 |  * @val:  the node | 
 | 1797 |  * | 
 | 1798 |  * checks whether @cur contains @val | 
 | 1799 |  * | 
 | 1800 |  * Returns true (1) if @cur contains @val, false (0) otherwise | 
 | 1801 |  */ | 
 | 1802 | int | 
 | 1803 | xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { | 
 | 1804 |     int i; | 
 | 1805 |  | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1806 |     if (val->type == XML_NAMESPACE_DECL) { | 
 | 1807 | 	for (i = 0; i < cur->nodeNr; i++) { | 
 | 1808 | 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { | 
 | 1809 | 		xmlNsPtr ns1, ns2; | 
 | 1810 |  | 
 | 1811 | 		ns1 = (xmlNsPtr) val; | 
 | 1812 | 		ns2 = (xmlNsPtr) cur->nodeTab[i]; | 
 | 1813 | 		if (ns1 == ns2) | 
 | 1814 | 		    return(1); | 
 | 1815 | 		if ((ns1->next != NULL) && (ns2->next == ns1->next) && | 
 | 1816 | 	            (xmlStrEqual(ns1->prefix, ns2->prefix))) | 
 | 1817 | 		    return(1); | 
 | 1818 | 	    } | 
 | 1819 | 	} | 
 | 1820 |     } else { | 
 | 1821 | 	for (i = 0; i < cur->nodeNr; i++) { | 
 | 1822 | 	    if (cur->nodeTab[i] == val) | 
 | 1823 | 		return(1); | 
 | 1824 | 	} | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 1825 |     } | 
 | 1826 |     return(0); | 
 | 1827 | } | 
 | 1828 |  | 
 | 1829 | /** | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1830 |  * xmlXPathNodeSetAddNs: | 
 | 1831 |  * @cur:  the initial node set | 
 | 1832 |  * @node:  the hosting node | 
 | 1833 |  * @ns:  a the namespace node | 
 | 1834 |  * | 
 | 1835 |  * add a new namespace node to an existing NodeSet | 
 | 1836 |  */ | 
| Aleksey Sanin | 79376ba | 2002-05-14 06:41:32 +0000 | [diff] [blame] | 1837 | void | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1838 | xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { | 
 | 1839 |     int i; | 
 | 1840 |  | 
 | 1841 |     if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) || | 
 | 1842 | 	(node->type != XML_ELEMENT_NODE)) | 
 | 1843 | 	return; | 
 | 1844 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1845 |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */ | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1846 |     /* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1847 |      * prevent duplicates | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1848 |      */ | 
 | 1849 |     for (i = 0;i < cur->nodeNr;i++) { | 
 | 1850 |         if ((cur->nodeTab[i] != NULL) && | 
 | 1851 | 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && | 
| Daniel Veillard | c62a147 | 2002-03-19 18:35:12 +0000 | [diff] [blame] | 1852 | 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1853 | 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) | 
 | 1854 | 	    return; | 
 | 1855 |     } | 
 | 1856 |  | 
 | 1857 |     /* | 
 | 1858 |      * grow the nodeTab if needed | 
 | 1859 |      */ | 
 | 1860 |     if (cur->nodeMax == 0) { | 
 | 1861 |         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * | 
 | 1862 | 					     sizeof(xmlNodePtr)); | 
 | 1863 | 	if (cur->nodeTab == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1864 | 	    xmlXPathErrMemory(NULL, "growing nodeset\n"); | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1865 | 	    return; | 
 | 1866 | 	} | 
 | 1867 | 	memset(cur->nodeTab, 0 , | 
 | 1868 | 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); | 
 | 1869 |         cur->nodeMax = XML_NODESET_DEFAULT; | 
 | 1870 |     } else if (cur->nodeNr == cur->nodeMax) { | 
 | 1871 |         xmlNodePtr *temp; | 
 | 1872 |  | 
 | 1873 |         cur->nodeMax *= 2; | 
 | 1874 | 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * | 
 | 1875 | 				      sizeof(xmlNodePtr)); | 
 | 1876 | 	if (temp == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1877 | 	    xmlXPathErrMemory(NULL, "growing nodeset\n"); | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1878 | 	    return; | 
 | 1879 | 	} | 
 | 1880 | 	cur->nodeTab = temp; | 
 | 1881 |     } | 
 | 1882 |     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); | 
 | 1883 | } | 
 | 1884 |  | 
 | 1885 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1886 |  * xmlXPathNodeSetAdd: | 
 | 1887 |  * @cur:  the initial node set | 
 | 1888 |  * @val:  a new xmlNodePtr | 
 | 1889 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 1890 |  * add a new xmlNodePtr to an existing NodeSet | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1891 |  */ | 
 | 1892 | void | 
 | 1893 | xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { | 
 | 1894 |     int i; | 
 | 1895 |  | 
 | 1896 |     if (val == NULL) return; | 
 | 1897 |  | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 1898 | #if 0 | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 1899 |     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) | 
 | 1900 | 	return;	/* an XSLT fake node */ | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 1901 | #endif | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 1902 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1903 |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1904 |     /* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1905 |      * prevent duplcates | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1906 |      */ | 
 | 1907 |     for (i = 0;i < cur->nodeNr;i++) | 
 | 1908 |         if (cur->nodeTab[i] == val) return; | 
 | 1909 |  | 
 | 1910 |     /* | 
 | 1911 |      * grow the nodeTab if needed | 
 | 1912 |      */ | 
 | 1913 |     if (cur->nodeMax == 0) { | 
 | 1914 |         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * | 
 | 1915 | 					     sizeof(xmlNodePtr)); | 
 | 1916 | 	if (cur->nodeTab == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1917 | 	    xmlXPathErrMemory(NULL, "growing nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1918 | 	    return; | 
 | 1919 | 	} | 
 | 1920 | 	memset(cur->nodeTab, 0 , | 
 | 1921 | 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); | 
 | 1922 |         cur->nodeMax = XML_NODESET_DEFAULT; | 
 | 1923 |     } else if (cur->nodeNr == cur->nodeMax) { | 
 | 1924 |         xmlNodePtr *temp; | 
 | 1925 |  | 
 | 1926 |         cur->nodeMax *= 2; | 
 | 1927 | 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * | 
 | 1928 | 				      sizeof(xmlNodePtr)); | 
 | 1929 | 	if (temp == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1930 | 	    xmlXPathErrMemory(NULL, "growing nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1931 | 	    return; | 
 | 1932 | 	} | 
 | 1933 | 	cur->nodeTab = temp; | 
 | 1934 |     } | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1935 |     if (val->type == XML_NAMESPACE_DECL) { | 
 | 1936 | 	xmlNsPtr ns = (xmlNsPtr) val; | 
 | 1937 |  | 
 | 1938 | 	cur->nodeTab[cur->nodeNr++] =  | 
 | 1939 | 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); | 
 | 1940 |     } else | 
 | 1941 | 	cur->nodeTab[cur->nodeNr++] = val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1942 | } | 
 | 1943 |  | 
 | 1944 | /** | 
 | 1945 |  * xmlXPathNodeSetAddUnique: | 
 | 1946 |  * @cur:  the initial node set | 
 | 1947 |  * @val:  a new xmlNodePtr | 
 | 1948 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 1949 |  * add a new xmlNodePtr to an existing NodeSet, optimized version | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1950 |  * when we are sure the node is not already in the set. | 
 | 1951 |  */ | 
 | 1952 | void | 
 | 1953 | xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { | 
 | 1954 |     if (val == NULL) return; | 
 | 1955 |  | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 1956 | #if 0 | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 1957 |     if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) | 
 | 1958 | 	return;	/* an XSLT fake node */ | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 1959 | #endif | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 1960 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 1961 |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1962 |     /* | 
 | 1963 |      * grow the nodeTab if needed | 
 | 1964 |      */ | 
 | 1965 |     if (cur->nodeMax == 0) { | 
 | 1966 |         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * | 
 | 1967 | 					     sizeof(xmlNodePtr)); | 
 | 1968 | 	if (cur->nodeTab == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1969 | 	    xmlXPathErrMemory(NULL, "growing nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1970 | 	    return; | 
 | 1971 | 	} | 
 | 1972 | 	memset(cur->nodeTab, 0 , | 
 | 1973 | 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); | 
 | 1974 |         cur->nodeMax = XML_NODESET_DEFAULT; | 
 | 1975 |     } else if (cur->nodeNr == cur->nodeMax) { | 
 | 1976 |         xmlNodePtr *temp; | 
 | 1977 |  | 
 | 1978 |         cur->nodeMax *= 2; | 
 | 1979 | 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * | 
 | 1980 | 				      sizeof(xmlNodePtr)); | 
 | 1981 | 	if (temp == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 1982 | 	    xmlXPathErrMemory(NULL, "growing nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1983 | 	    return; | 
 | 1984 | 	} | 
 | 1985 | 	cur->nodeTab = temp; | 
 | 1986 |     } | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 1987 |     if (val->type == XML_NAMESPACE_DECL) { | 
 | 1988 | 	xmlNsPtr ns = (xmlNsPtr) val; | 
 | 1989 |  | 
 | 1990 | 	cur->nodeTab[cur->nodeNr++] =  | 
 | 1991 | 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); | 
 | 1992 |     } else | 
 | 1993 | 	cur->nodeTab[cur->nodeNr++] = val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 1994 | } | 
 | 1995 |  | 
 | 1996 | /** | 
 | 1997 |  * xmlXPathNodeSetMerge: | 
 | 1998 |  * @val1:  the first NodeSet or NULL | 
 | 1999 |  * @val2:  the second NodeSet | 
 | 2000 |  * | 
 | 2001 |  * Merges two nodesets, all nodes from @val2 are added to @val1 | 
 | 2002 |  * if @val1 is NULL, a new set is created and copied from @val2 | 
 | 2003 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 2004 |  * Returns @val1 once extended or NULL in case of error. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2005 |  */ | 
 | 2006 | xmlNodeSetPtr | 
 | 2007 | xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 2008 |     int i, j, initNr, skip; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2009 |  | 
 | 2010 |     if (val2 == NULL) return(val1); | 
 | 2011 |     if (val1 == NULL) { | 
 | 2012 | 	val1 = xmlXPathNodeSetCreate(NULL); | 
 | 2013 |     } | 
 | 2014 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2015 |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2016 |     initNr = val1->nodeNr; | 
 | 2017 |  | 
 | 2018 |     for (i = 0;i < val2->nodeNr;i++) { | 
 | 2019 | 	/* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2020 | 	 * check against duplicates | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2021 | 	 */ | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 2022 | 	skip = 0; | 
 | 2023 | 	for (j = 0; j < initNr; j++) { | 
 | 2024 | 	    if (val1->nodeTab[j] == val2->nodeTab[i]) { | 
 | 2025 | 		skip = 1; | 
 | 2026 | 		break; | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2027 | 	    } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) && | 
 | 2028 | 		       (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) { | 
 | 2029 | 		xmlNsPtr ns1, ns2; | 
 | 2030 | 		ns1 = (xmlNsPtr) val1->nodeTab[j]; | 
 | 2031 | 		ns2 = (xmlNsPtr) val2->nodeTab[i]; | 
 | 2032 | 		if ((ns1->next == ns2->next) && | 
 | 2033 | 		    (xmlStrEqual(ns1->prefix, ns2->prefix))) { | 
 | 2034 | 		    skip = 1; | 
 | 2035 | 		    break; | 
 | 2036 | 		} | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 2037 | 	    } | 
 | 2038 | 	} | 
 | 2039 | 	if (skip) | 
 | 2040 | 	    continue; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2041 |  | 
 | 2042 | 	/* | 
 | 2043 | 	 * grow the nodeTab if needed | 
 | 2044 | 	 */ | 
 | 2045 | 	if (val1->nodeMax == 0) { | 
 | 2046 | 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * | 
 | 2047 | 						    sizeof(xmlNodePtr)); | 
 | 2048 | 	    if (val1->nodeTab == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 2049 | 	        xmlXPathErrMemory(NULL, "merging nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2050 | 		return(NULL); | 
 | 2051 | 	    } | 
 | 2052 | 	    memset(val1->nodeTab, 0 , | 
 | 2053 | 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); | 
 | 2054 | 	    val1->nodeMax = XML_NODESET_DEFAULT; | 
 | 2055 | 	} else if (val1->nodeNr == val1->nodeMax) { | 
 | 2056 | 	    xmlNodePtr *temp; | 
 | 2057 |  | 
 | 2058 | 	    val1->nodeMax *= 2; | 
 | 2059 | 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * | 
 | 2060 | 					     sizeof(xmlNodePtr)); | 
 | 2061 | 	    if (temp == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 2062 | 	        xmlXPathErrMemory(NULL, "merging nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2063 | 		return(NULL); | 
 | 2064 | 	    } | 
 | 2065 | 	    val1->nodeTab = temp; | 
 | 2066 | 	} | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2067 | 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { | 
 | 2068 | 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; | 
 | 2069 |  | 
 | 2070 | 	    val1->nodeTab[val1->nodeNr++] = | 
 | 2071 | 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); | 
 | 2072 | 	} else | 
 | 2073 | 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2074 |     } | 
 | 2075 |  | 
 | 2076 |     return(val1); | 
 | 2077 | } | 
 | 2078 |  | 
 | 2079 | /** | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 2080 |  * xmlXPathNodeSetMergeUnique: | 
 | 2081 |  * @val1:  the first NodeSet or NULL | 
 | 2082 |  * @val2:  the second NodeSet | 
 | 2083 |  * | 
 | 2084 |  * Merges two nodesets, all nodes from @val2 are added to @val1 | 
 | 2085 |  * if @val1 is NULL, a new set is created and copied from @val2 | 
 | 2086 |  * | 
 | 2087 |  * Returns @val1 once extended or NULL in case of error. | 
 | 2088 |  */ | 
 | 2089 | static xmlNodeSetPtr | 
 | 2090 | xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 2091 |     int i; | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 2092 |  | 
 | 2093 |     if (val2 == NULL) return(val1); | 
 | 2094 |     if (val1 == NULL) { | 
 | 2095 | 	val1 = xmlXPathNodeSetCreate(NULL); | 
 | 2096 |     } | 
 | 2097 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2098 |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */ | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 2099 |  | 
 | 2100 |     for (i = 0;i < val2->nodeNr;i++) { | 
 | 2101 | 	/* | 
 | 2102 | 	 * grow the nodeTab if needed | 
 | 2103 | 	 */ | 
 | 2104 | 	if (val1->nodeMax == 0) { | 
 | 2105 | 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * | 
 | 2106 | 						    sizeof(xmlNodePtr)); | 
 | 2107 | 	    if (val1->nodeTab == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 2108 | 	        xmlXPathErrMemory(NULL, "merging nodeset\n"); | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 2109 | 		return(NULL); | 
 | 2110 | 	    } | 
 | 2111 | 	    memset(val1->nodeTab, 0 , | 
 | 2112 | 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); | 
 | 2113 | 	    val1->nodeMax = XML_NODESET_DEFAULT; | 
 | 2114 | 	} else if (val1->nodeNr == val1->nodeMax) { | 
 | 2115 | 	    xmlNodePtr *temp; | 
 | 2116 |  | 
 | 2117 | 	    val1->nodeMax *= 2; | 
 | 2118 | 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * | 
 | 2119 | 					     sizeof(xmlNodePtr)); | 
 | 2120 | 	    if (temp == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 2121 | 	        xmlXPathErrMemory(NULL, "merging nodeset\n"); | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 2122 | 		return(NULL); | 
 | 2123 | 	    } | 
 | 2124 | 	    val1->nodeTab = temp; | 
 | 2125 | 	} | 
 | 2126 | 	if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { | 
 | 2127 | 	    xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; | 
 | 2128 |  | 
 | 2129 | 	    val1->nodeTab[val1->nodeNr++] = | 
 | 2130 | 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); | 
 | 2131 | 	} else | 
 | 2132 | 	    val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; | 
 | 2133 |     } | 
 | 2134 |  | 
 | 2135 |     return(val1); | 
 | 2136 | } | 
 | 2137 |  | 
 | 2138 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2139 |  * xmlXPathNodeSetDel: | 
 | 2140 |  * @cur:  the initial node set | 
 | 2141 |  * @val:  an xmlNodePtr | 
 | 2142 |  * | 
 | 2143 |  * Removes an xmlNodePtr from an existing NodeSet | 
 | 2144 |  */ | 
 | 2145 | void | 
 | 2146 | xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { | 
 | 2147 |     int i; | 
 | 2148 |  | 
 | 2149 |     if (cur == NULL) return; | 
 | 2150 |     if (val == NULL) return; | 
 | 2151 |  | 
 | 2152 |     /* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2153 |      * find node in nodeTab | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2154 |      */ | 
 | 2155 |     for (i = 0;i < cur->nodeNr;i++) | 
 | 2156 |         if (cur->nodeTab[i] == val) break; | 
 | 2157 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2158 |     if (i >= cur->nodeNr) {	/* not found */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2159 | #ifdef DEBUG | 
 | 2160 |         xmlGenericError(xmlGenericErrorContext,  | 
 | 2161 | 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", | 
 | 2162 | 		val->name); | 
 | 2163 | #endif | 
 | 2164 |         return; | 
 | 2165 |     } | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2166 |     if ((cur->nodeTab[i] != NULL) && | 
 | 2167 | 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) | 
 | 2168 | 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2169 |     cur->nodeNr--; | 
 | 2170 |     for (;i < cur->nodeNr;i++) | 
 | 2171 |         cur->nodeTab[i] = cur->nodeTab[i + 1]; | 
 | 2172 |     cur->nodeTab[cur->nodeNr] = NULL; | 
 | 2173 | } | 
 | 2174 |  | 
 | 2175 | /** | 
 | 2176 |  * xmlXPathNodeSetRemove: | 
 | 2177 |  * @cur:  the initial node set | 
 | 2178 |  * @val:  the index to remove | 
 | 2179 |  * | 
 | 2180 |  * Removes an entry from an existing NodeSet list. | 
 | 2181 |  */ | 
 | 2182 | void | 
 | 2183 | xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { | 
 | 2184 |     if (cur == NULL) return; | 
 | 2185 |     if (val >= cur->nodeNr) return; | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2186 |     if ((cur->nodeTab[val] != NULL) && | 
 | 2187 | 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) | 
 | 2188 | 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2189 |     cur->nodeNr--; | 
 | 2190 |     for (;val < cur->nodeNr;val++) | 
 | 2191 |         cur->nodeTab[val] = cur->nodeTab[val + 1]; | 
 | 2192 |     cur->nodeTab[cur->nodeNr] = NULL; | 
 | 2193 | } | 
 | 2194 |  | 
 | 2195 | /** | 
 | 2196 |  * xmlXPathFreeNodeSet: | 
 | 2197 |  * @obj:  the xmlNodeSetPtr to free | 
 | 2198 |  * | 
 | 2199 |  * Free the NodeSet compound (not the actual nodes !). | 
 | 2200 |  */ | 
 | 2201 | void | 
 | 2202 | xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { | 
 | 2203 |     if (obj == NULL) return; | 
 | 2204 |     if (obj->nodeTab != NULL) { | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2205 | 	int i; | 
 | 2206 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2207 | 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */ | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2208 | 	for (i = 0;i < obj->nodeNr;i++) | 
 | 2209 | 	    if ((obj->nodeTab[i] != NULL) && | 
 | 2210 | 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) | 
 | 2211 | 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2212 | 	xmlFree(obj->nodeTab); | 
 | 2213 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2214 |     xmlFree(obj); | 
 | 2215 | } | 
 | 2216 |  | 
 | 2217 | /** | 
 | 2218 |  * xmlXPathFreeValueTree: | 
 | 2219 |  * @obj:  the xmlNodeSetPtr to free | 
 | 2220 |  * | 
 | 2221 |  * Free the NodeSet compound and the actual tree, this is different | 
 | 2222 |  * from xmlXPathFreeNodeSet() | 
 | 2223 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 2224 | static void | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2225 | xmlXPathFreeValueTree(xmlNodeSetPtr obj) { | 
 | 2226 |     int i; | 
 | 2227 |  | 
 | 2228 |     if (obj == NULL) return; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2229 |  | 
 | 2230 |     if (obj->nodeTab != NULL) { | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2231 | 	for (i = 0;i < obj->nodeNr;i++) { | 
 | 2232 | 	    if (obj->nodeTab[i] != NULL) { | 
 | 2233 | 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { | 
 | 2234 | 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); | 
 | 2235 | 		} else { | 
 | 2236 | 		    xmlFreeNodeList(obj->nodeTab[i]); | 
 | 2237 | 		} | 
 | 2238 | 	    } | 
 | 2239 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2240 | 	xmlFree(obj->nodeTab); | 
 | 2241 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2242 |     xmlFree(obj); | 
 | 2243 | } | 
 | 2244 |  | 
 | 2245 | #if defined(DEBUG) || defined(DEBUG_STEP) | 
 | 2246 | /** | 
 | 2247 |  * xmlGenericErrorContextNodeSet: | 
 | 2248 |  * @output:  a FILE * for the output | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2249 |  * @obj:  the xmlNodeSetPtr to display | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2250 |  * | 
 | 2251 |  * Quick display of a NodeSet | 
 | 2252 |  */ | 
 | 2253 | void | 
 | 2254 | xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { | 
 | 2255 |     int i; | 
 | 2256 |  | 
 | 2257 |     if (output == NULL) output = xmlGenericErrorContext; | 
 | 2258 |     if (obj == NULL)  { | 
 | 2259 |         fprintf(output, "NodeSet == NULL !\n"); | 
 | 2260 | 	return; | 
 | 2261 |     } | 
 | 2262 |     if (obj->nodeNr == 0) { | 
 | 2263 |         fprintf(output, "NodeSet is empty\n"); | 
 | 2264 | 	return; | 
 | 2265 |     } | 
 | 2266 |     if (obj->nodeTab == NULL) { | 
 | 2267 | 	fprintf(output, " nodeTab == NULL !\n"); | 
 | 2268 | 	return; | 
 | 2269 |     } | 
 | 2270 |     for (i = 0; i < obj->nodeNr; i++) { | 
 | 2271 |         if (obj->nodeTab[i] == NULL) { | 
 | 2272 | 	    fprintf(output, " NULL !\n"); | 
 | 2273 | 	    return; | 
 | 2274 |         } | 
 | 2275 | 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || | 
 | 2276 | 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) | 
 | 2277 | 	    fprintf(output, " /"); | 
 | 2278 | 	else if (obj->nodeTab[i]->name == NULL) | 
 | 2279 | 	    fprintf(output, " noname!"); | 
 | 2280 | 	else fprintf(output, " %s", obj->nodeTab[i]->name); | 
 | 2281 |     } | 
 | 2282 |     fprintf(output, "\n"); | 
 | 2283 | } | 
 | 2284 | #endif | 
 | 2285 |  | 
 | 2286 | /** | 
 | 2287 |  * xmlXPathNewNodeSet: | 
 | 2288 |  * @val:  the NodePtr value | 
 | 2289 |  * | 
 | 2290 |  * Create a new xmlXPathObjectPtr of type NodeSet and initialize | 
 | 2291 |  * it with the single Node @val | 
 | 2292 |  * | 
 | 2293 |  * Returns the newly created object. | 
 | 2294 |  */ | 
 | 2295 | xmlXPathObjectPtr | 
 | 2296 | xmlXPathNewNodeSet(xmlNodePtr val) { | 
 | 2297 |     xmlXPathObjectPtr ret; | 
 | 2298 |  | 
 | 2299 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 2300 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 2301 |         xmlXPathErrMemory(NULL, "creating nodeset\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2302 | 	return(NULL); | 
 | 2303 |     } | 
 | 2304 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 2305 |     ret->type = XPATH_NODESET; | 
| Daniel Veillard | 7785171 | 2001-02-27 21:54:07 +0000 | [diff] [blame] | 2306 |     ret->boolval = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2307 |     ret->nodesetval = xmlXPathNodeSetCreate(val); | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2308 |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2309 |     return(ret); | 
 | 2310 | } | 
 | 2311 |  | 
 | 2312 | /** | 
 | 2313 |  * xmlXPathNewValueTree: | 
 | 2314 |  * @val:  the NodePtr value | 
 | 2315 |  * | 
 | 2316 |  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize | 
 | 2317 |  * it with the tree root @val | 
 | 2318 |  * | 
 | 2319 |  * Returns the newly created object. | 
 | 2320 |  */ | 
 | 2321 | xmlXPathObjectPtr | 
 | 2322 | xmlXPathNewValueTree(xmlNodePtr val) { | 
 | 2323 |     xmlXPathObjectPtr ret; | 
 | 2324 |  | 
 | 2325 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 2326 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 2327 |         xmlXPathErrMemory(NULL, "creating result value tree\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2328 | 	return(NULL); | 
 | 2329 |     } | 
 | 2330 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 2331 |     ret->type = XPATH_XSLT_TREE; | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 2332 |     ret->boolval = 1; | 
 | 2333 |     ret->user = (void *) val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2334 |     ret->nodesetval = xmlXPathNodeSetCreate(val); | 
 | 2335 |     return(ret); | 
 | 2336 | } | 
 | 2337 |  | 
 | 2338 | /** | 
 | 2339 |  * xmlXPathNewNodeSetList: | 
 | 2340 |  * @val:  an existing NodeSet | 
 | 2341 |  * | 
 | 2342 |  * Create a new xmlXPathObjectPtr of type NodeSet and initialize | 
 | 2343 |  * it with the Nodeset @val | 
 | 2344 |  * | 
 | 2345 |  * Returns the newly created object. | 
 | 2346 |  */ | 
 | 2347 | xmlXPathObjectPtr | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2348 | xmlXPathNewNodeSetList(xmlNodeSetPtr val) | 
 | 2349 | { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2350 |     xmlXPathObjectPtr ret; | 
 | 2351 |     int i; | 
 | 2352 |  | 
 | 2353 |     if (val == NULL) | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2354 |         ret = NULL; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2355 |     else if (val->nodeTab == NULL) | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2356 |         ret = xmlXPathNewNodeSet(NULL); | 
 | 2357 |     else { | 
 | 2358 |         ret = xmlXPathNewNodeSet(val->nodeTab[0]); | 
 | 2359 |         for (i = 1; i < val->nodeNr; ++i) | 
 | 2360 |             xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); | 
 | 2361 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2362 |  | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 2363 |     return (ret); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2364 | } | 
 | 2365 |  | 
 | 2366 | /** | 
 | 2367 |  * xmlXPathWrapNodeSet: | 
 | 2368 |  * @val:  the NodePtr value | 
 | 2369 |  * | 
 | 2370 |  * Wrap the Nodeset @val in a new xmlXPathObjectPtr | 
 | 2371 |  * | 
 | 2372 |  * Returns the newly created object. | 
 | 2373 |  */ | 
 | 2374 | xmlXPathObjectPtr | 
 | 2375 | xmlXPathWrapNodeSet(xmlNodeSetPtr val) { | 
 | 2376 |     xmlXPathObjectPtr ret; | 
 | 2377 |  | 
 | 2378 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 2379 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 2380 |         xmlXPathErrMemory(NULL, "creating node set object\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2381 | 	return(NULL); | 
 | 2382 |     } | 
 | 2383 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 2384 |     ret->type = XPATH_NODESET; | 
 | 2385 |     ret->nodesetval = val; | 
 | 2386 |     return(ret); | 
 | 2387 | } | 
 | 2388 |  | 
 | 2389 | /** | 
 | 2390 |  * xmlXPathFreeNodeSetList: | 
 | 2391 |  * @obj:  an existing NodeSetList object | 
 | 2392 |  * | 
 | 2393 |  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in | 
 | 2394 |  * the list contrary to xmlXPathFreeObject(). | 
 | 2395 |  */ | 
 | 2396 | void | 
 | 2397 | xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { | 
 | 2398 |     if (obj == NULL) return; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2399 |     xmlFree(obj); | 
 | 2400 | } | 
 | 2401 |  | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 2402 | /** | 
 | 2403 |  * xmlXPathDifference: | 
 | 2404 |  * @nodes1:  a node-set | 
 | 2405 |  * @nodes2:  a node-set | 
 | 2406 |  * | 
 | 2407 |  * Implements the EXSLT - Sets difference() function: | 
 | 2408 |  *    node-set set:difference (node-set, node-set) | 
 | 2409 |  * | 
 | 2410 |  * Returns the difference between the two node sets, or nodes1 if | 
 | 2411 |  *         nodes2 is empty | 
 | 2412 |  */ | 
 | 2413 | xmlNodeSetPtr | 
 | 2414 | xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
 | 2415 |     xmlNodeSetPtr ret; | 
 | 2416 |     int i, l1; | 
 | 2417 |     xmlNodePtr cur; | 
 | 2418 |  | 
 | 2419 |     if (xmlXPathNodeSetIsEmpty(nodes2)) | 
 | 2420 | 	return(nodes1); | 
 | 2421 |  | 
 | 2422 |     ret = xmlXPathNodeSetCreate(NULL); | 
 | 2423 |     if (xmlXPathNodeSetIsEmpty(nodes1)) | 
 | 2424 | 	return(ret); | 
 | 2425 |  | 
 | 2426 |     l1 = xmlXPathNodeSetGetLength(nodes1); | 
 | 2427 |  | 
 | 2428 |     for (i = 0; i < l1; i++) { | 
 | 2429 | 	cur = xmlXPathNodeSetItem(nodes1, i); | 
 | 2430 | 	if (!xmlXPathNodeSetContains(nodes2, cur)) | 
 | 2431 | 	    xmlXPathNodeSetAddUnique(ret, cur); | 
 | 2432 |     } | 
 | 2433 |     return(ret); | 
 | 2434 | } | 
 | 2435 |  | 
 | 2436 | /** | 
 | 2437 |  * xmlXPathIntersection: | 
 | 2438 |  * @nodes1:  a node-set | 
 | 2439 |  * @nodes2:  a node-set | 
 | 2440 |  * | 
 | 2441 |  * Implements the EXSLT - Sets intersection() function: | 
 | 2442 |  *    node-set set:intersection (node-set, node-set) | 
 | 2443 |  * | 
 | 2444 |  * Returns a node set comprising the nodes that are within both the | 
 | 2445 |  *         node sets passed as arguments | 
 | 2446 |  */ | 
 | 2447 | xmlNodeSetPtr | 
 | 2448 | xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
 | 2449 |     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); | 
 | 2450 |     int i, l1; | 
 | 2451 |     xmlNodePtr cur; | 
 | 2452 |  | 
 | 2453 |     if (xmlXPathNodeSetIsEmpty(nodes1)) | 
 | 2454 | 	return(ret); | 
 | 2455 |     if (xmlXPathNodeSetIsEmpty(nodes2)) | 
 | 2456 | 	return(ret); | 
 | 2457 |  | 
 | 2458 |     l1 = xmlXPathNodeSetGetLength(nodes1); | 
 | 2459 |  | 
 | 2460 |     for (i = 0; i < l1; i++) { | 
 | 2461 | 	cur = xmlXPathNodeSetItem(nodes1, i); | 
 | 2462 | 	if (xmlXPathNodeSetContains(nodes2, cur)) | 
 | 2463 | 	    xmlXPathNodeSetAddUnique(ret, cur); | 
 | 2464 |     } | 
 | 2465 |     return(ret); | 
 | 2466 | } | 
 | 2467 |  | 
 | 2468 | /** | 
 | 2469 |  * xmlXPathDistinctSorted: | 
 | 2470 |  * @nodes:  a node-set, sorted by document order | 
 | 2471 |  * | 
 | 2472 |  * Implements the EXSLT - Sets distinct() function: | 
 | 2473 |  *    node-set set:distinct (node-set) | 
 | 2474 |  *  | 
 | 2475 |  * Returns a subset of the nodes contained in @nodes, or @nodes if | 
 | 2476 |  *         it is empty | 
 | 2477 |  */ | 
 | 2478 | xmlNodeSetPtr | 
 | 2479 | xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { | 
 | 2480 |     xmlNodeSetPtr ret; | 
 | 2481 |     xmlHashTablePtr hash; | 
 | 2482 |     int i, l; | 
 | 2483 |     xmlChar * strval; | 
 | 2484 |     xmlNodePtr cur; | 
 | 2485 |  | 
 | 2486 |     if (xmlXPathNodeSetIsEmpty(nodes)) | 
 | 2487 | 	return(nodes); | 
 | 2488 |  | 
 | 2489 |     ret = xmlXPathNodeSetCreate(NULL); | 
 | 2490 |     l = xmlXPathNodeSetGetLength(nodes); | 
 | 2491 |     hash = xmlHashCreate (l); | 
 | 2492 |     for (i = 0; i < l; i++) { | 
 | 2493 | 	cur = xmlXPathNodeSetItem(nodes, i); | 
 | 2494 | 	strval = xmlXPathCastNodeToString(cur); | 
 | 2495 | 	if (xmlHashLookup(hash, strval) == NULL) { | 
 | 2496 | 	    xmlHashAddEntry(hash, strval, strval); | 
 | 2497 | 	    xmlXPathNodeSetAddUnique(ret, cur); | 
 | 2498 | 	} else { | 
 | 2499 | 	    xmlFree(strval); | 
 | 2500 | 	} | 
 | 2501 |     } | 
 | 2502 |     xmlHashFree(hash, (xmlHashDeallocator) xmlFree); | 
 | 2503 |     return(ret); | 
 | 2504 | } | 
 | 2505 |  | 
 | 2506 | /** | 
 | 2507 |  * xmlXPathDistinct: | 
 | 2508 |  * @nodes:  a node-set | 
 | 2509 |  * | 
 | 2510 |  * Implements the EXSLT - Sets distinct() function: | 
 | 2511 |  *    node-set set:distinct (node-set) | 
 | 2512 |  * @nodes is sorted by document order, then #exslSetsDistinctSorted | 
 | 2513 |  * is called with the sorted node-set | 
 | 2514 |  * | 
 | 2515 |  * Returns a subset of the nodes contained in @nodes, or @nodes if | 
 | 2516 |  *         it is empty | 
 | 2517 |  */ | 
 | 2518 | xmlNodeSetPtr | 
 | 2519 | xmlXPathDistinct (xmlNodeSetPtr nodes) { | 
 | 2520 |     if (xmlXPathNodeSetIsEmpty(nodes)) | 
 | 2521 | 	return(nodes); | 
 | 2522 |  | 
 | 2523 |     xmlXPathNodeSetSort(nodes); | 
 | 2524 |     return(xmlXPathDistinctSorted(nodes)); | 
 | 2525 | } | 
 | 2526 |  | 
 | 2527 | /** | 
 | 2528 |  * xmlXPathHasSameNodes: | 
 | 2529 |  * @nodes1:  a node-set | 
 | 2530 |  * @nodes2:  a node-set | 
 | 2531 |  * | 
 | 2532 |  * Implements the EXSLT - Sets has-same-nodes function: | 
 | 2533 |  *    boolean set:has-same-node(node-set, node-set) | 
 | 2534 |  * | 
 | 2535 |  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) | 
 | 2536 |  *         otherwise | 
 | 2537 |  */ | 
 | 2538 | int | 
 | 2539 | xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
 | 2540 |     int i, l; | 
 | 2541 |     xmlNodePtr cur; | 
 | 2542 |  | 
 | 2543 |     if (xmlXPathNodeSetIsEmpty(nodes1) || | 
 | 2544 | 	xmlXPathNodeSetIsEmpty(nodes2)) | 
 | 2545 | 	return(0); | 
 | 2546 |  | 
 | 2547 |     l = xmlXPathNodeSetGetLength(nodes1); | 
 | 2548 |     for (i = 0; i < l; i++) { | 
 | 2549 | 	cur = xmlXPathNodeSetItem(nodes1, i); | 
 | 2550 | 	if (xmlXPathNodeSetContains(nodes2, cur)) | 
 | 2551 | 	    return(1); | 
 | 2552 |     } | 
 | 2553 |     return(0); | 
 | 2554 | } | 
 | 2555 |  | 
 | 2556 | /** | 
 | 2557 |  * xmlXPathNodeLeadingSorted: | 
 | 2558 |  * @nodes: a node-set, sorted by document order | 
 | 2559 |  * @node: a node | 
 | 2560 |  * | 
 | 2561 |  * Implements the EXSLT - Sets leading() function: | 
 | 2562 |  *    node-set set:leading (node-set, node-set) | 
 | 2563 |  * | 
 | 2564 |  * Returns the nodes in @nodes that precede @node in document order, | 
 | 2565 |  *         @nodes if @node is NULL or an empty node-set if @nodes | 
 | 2566 |  *         doesn't contain @node | 
 | 2567 |  */ | 
 | 2568 | xmlNodeSetPtr | 
 | 2569 | xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
 | 2570 |     int i, l; | 
 | 2571 |     xmlNodePtr cur; | 
 | 2572 |     xmlNodeSetPtr ret; | 
 | 2573 |  | 
 | 2574 |     if (node == NULL) | 
 | 2575 | 	return(nodes); | 
 | 2576 |  | 
 | 2577 |     ret = xmlXPathNodeSetCreate(NULL); | 
 | 2578 |     if (xmlXPathNodeSetIsEmpty(nodes) || | 
 | 2579 | 	(!xmlXPathNodeSetContains(nodes, node))) | 
 | 2580 | 	return(ret); | 
 | 2581 |  | 
 | 2582 |     l = xmlXPathNodeSetGetLength(nodes); | 
 | 2583 |     for (i = 0; i < l; i++) { | 
 | 2584 | 	cur = xmlXPathNodeSetItem(nodes, i); | 
 | 2585 | 	if (cur == node) | 
 | 2586 | 	    break; | 
 | 2587 | 	xmlXPathNodeSetAddUnique(ret, cur); | 
 | 2588 |     } | 
 | 2589 |     return(ret); | 
 | 2590 | } | 
 | 2591 |  | 
 | 2592 | /** | 
 | 2593 |  * xmlXPathNodeLeading: | 
 | 2594 |  * @nodes:  a node-set | 
 | 2595 |  * @node:  a node | 
 | 2596 |  * | 
 | 2597 |  * Implements the EXSLT - Sets leading() function: | 
 | 2598 |  *    node-set set:leading (node-set, node-set) | 
 | 2599 |  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted | 
 | 2600 |  * is called. | 
 | 2601 |  * | 
 | 2602 |  * Returns the nodes in @nodes that precede @node in document order, | 
 | 2603 |  *         @nodes if @node is NULL or an empty node-set if @nodes | 
 | 2604 |  *         doesn't contain @node | 
 | 2605 |  */ | 
 | 2606 | xmlNodeSetPtr | 
 | 2607 | xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
 | 2608 |     xmlXPathNodeSetSort(nodes); | 
 | 2609 |     return(xmlXPathNodeLeadingSorted(nodes, node)); | 
 | 2610 | } | 
 | 2611 |  | 
 | 2612 | /** | 
 | 2613 |  * xmlXPathLeadingSorted: | 
 | 2614 |  * @nodes1:  a node-set, sorted by document order | 
 | 2615 |  * @nodes2:  a node-set, sorted by document order | 
 | 2616 |  * | 
 | 2617 |  * Implements the EXSLT - Sets leading() function: | 
 | 2618 |  *    node-set set:leading (node-set, node-set) | 
 | 2619 |  * | 
 | 2620 |  * Returns the nodes in @nodes1 that precede the first node in @nodes2 | 
 | 2621 |  *         in document order, @nodes1 if @nodes2 is NULL or empty or | 
 | 2622 |  *         an empty node-set if @nodes1 doesn't contain @nodes2 | 
 | 2623 |  */ | 
 | 2624 | xmlNodeSetPtr | 
 | 2625 | xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
 | 2626 |     if (xmlXPathNodeSetIsEmpty(nodes2)) | 
 | 2627 | 	return(nodes1); | 
 | 2628 |     return(xmlXPathNodeLeadingSorted(nodes1, | 
 | 2629 | 				     xmlXPathNodeSetItem(nodes2, 1))); | 
 | 2630 | } | 
 | 2631 |  | 
 | 2632 | /** | 
 | 2633 |  * xmlXPathLeading: | 
 | 2634 |  * @nodes1:  a node-set | 
 | 2635 |  * @nodes2:  a node-set | 
 | 2636 |  * | 
 | 2637 |  * Implements the EXSLT - Sets leading() function: | 
 | 2638 |  *    node-set set:leading (node-set, node-set) | 
 | 2639 |  * @nodes1 and @nodes2 are sorted by document order, then | 
 | 2640 |  * #exslSetsLeadingSorted is called. | 
 | 2641 |  * | 
 | 2642 |  * Returns the nodes in @nodes1 that precede the first node in @nodes2 | 
 | 2643 |  *         in document order, @nodes1 if @nodes2 is NULL or empty or | 
 | 2644 |  *         an empty node-set if @nodes1 doesn't contain @nodes2 | 
 | 2645 |  */ | 
 | 2646 | xmlNodeSetPtr | 
 | 2647 | xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
 | 2648 |     if (xmlXPathNodeSetIsEmpty(nodes2)) | 
 | 2649 | 	return(nodes1); | 
 | 2650 |     if (xmlXPathNodeSetIsEmpty(nodes1)) | 
 | 2651 | 	return(xmlXPathNodeSetCreate(NULL)); | 
 | 2652 |     xmlXPathNodeSetSort(nodes1); | 
 | 2653 |     xmlXPathNodeSetSort(nodes2); | 
 | 2654 |     return(xmlXPathNodeLeadingSorted(nodes1, | 
 | 2655 | 				     xmlXPathNodeSetItem(nodes2, 1))); | 
 | 2656 | } | 
 | 2657 |  | 
 | 2658 | /** | 
 | 2659 |  * xmlXPathNodeTrailingSorted: | 
 | 2660 |  * @nodes: a node-set, sorted by document order | 
 | 2661 |  * @node: a node | 
 | 2662 |  * | 
 | 2663 |  * Implements the EXSLT - Sets trailing() function: | 
 | 2664 |  *    node-set set:trailing (node-set, node-set) | 
 | 2665 |  * | 
 | 2666 |  * Returns the nodes in @nodes that follow @node in document order, | 
 | 2667 |  *         @nodes if @node is NULL or an empty node-set if @nodes | 
 | 2668 |  *         doesn't contain @node | 
 | 2669 |  */ | 
 | 2670 | xmlNodeSetPtr | 
 | 2671 | xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
 | 2672 |     int i, l; | 
 | 2673 |     xmlNodePtr cur; | 
 | 2674 |     xmlNodeSetPtr ret; | 
 | 2675 |  | 
 | 2676 |     if (node == NULL) | 
 | 2677 | 	return(nodes); | 
 | 2678 |  | 
 | 2679 |     ret = xmlXPathNodeSetCreate(NULL); | 
 | 2680 |     if (xmlXPathNodeSetIsEmpty(nodes) || | 
 | 2681 | 	(!xmlXPathNodeSetContains(nodes, node))) | 
 | 2682 | 	return(ret); | 
 | 2683 |  | 
 | 2684 |     l = xmlXPathNodeSetGetLength(nodes); | 
| Thomas Broyer | f186c82 | 2001-07-31 23:30:37 +0000 | [diff] [blame] | 2685 |     for (i = l; i > 0; i--) { | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 2686 | 	cur = xmlXPathNodeSetItem(nodes, i); | 
 | 2687 | 	if (cur == node) | 
 | 2688 | 	    break; | 
 | 2689 | 	xmlXPathNodeSetAddUnique(ret, cur); | 
 | 2690 |     } | 
 | 2691 |     return(ret); | 
 | 2692 | } | 
 | 2693 |  | 
 | 2694 | /** | 
 | 2695 |  * xmlXPathNodeTrailing: | 
 | 2696 |  * @nodes:  a node-set | 
 | 2697 |  * @node:  a node | 
 | 2698 |  * | 
 | 2699 |  * Implements the EXSLT - Sets trailing() function: | 
 | 2700 |  *    node-set set:trailing (node-set, node-set) | 
 | 2701 |  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted | 
 | 2702 |  * is called. | 
 | 2703 |  * | 
 | 2704 |  * Returns the nodes in @nodes that follow @node in document order, | 
 | 2705 |  *         @nodes if @node is NULL or an empty node-set if @nodes | 
 | 2706 |  *         doesn't contain @node | 
 | 2707 |  */ | 
 | 2708 | xmlNodeSetPtr | 
 | 2709 | xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
 | 2710 |     xmlXPathNodeSetSort(nodes); | 
 | 2711 |     return(xmlXPathNodeTrailingSorted(nodes, node)); | 
 | 2712 | } | 
 | 2713 |  | 
 | 2714 | /** | 
 | 2715 |  * xmlXPathTrailingSorted: | 
 | 2716 |  * @nodes1:  a node-set, sorted by document order | 
 | 2717 |  * @nodes2:  a node-set, sorted by document order | 
 | 2718 |  * | 
 | 2719 |  * Implements the EXSLT - Sets trailing() function: | 
 | 2720 |  *    node-set set:trailing (node-set, node-set) | 
 | 2721 |  * | 
 | 2722 |  * Returns the nodes in @nodes1 that follow the first node in @nodes2 | 
 | 2723 |  *         in document order, @nodes1 if @nodes2 is NULL or empty or | 
 | 2724 |  *         an empty node-set if @nodes1 doesn't contain @nodes2 | 
 | 2725 |  */ | 
 | 2726 | xmlNodeSetPtr | 
 | 2727 | xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
 | 2728 |     if (xmlXPathNodeSetIsEmpty(nodes2)) | 
 | 2729 | 	return(nodes1); | 
 | 2730 |     return(xmlXPathNodeTrailingSorted(nodes1, | 
 | 2731 | 				      xmlXPathNodeSetItem(nodes2, 0))); | 
 | 2732 | } | 
 | 2733 |  | 
 | 2734 | /** | 
 | 2735 |  * xmlXPathTrailing: | 
 | 2736 |  * @nodes1:  a node-set | 
 | 2737 |  * @nodes2:  a node-set | 
 | 2738 |  * | 
 | 2739 |  * Implements the EXSLT - Sets trailing() function: | 
 | 2740 |  *    node-set set:trailing (node-set, node-set) | 
 | 2741 |  * @nodes1 and @nodes2 are sorted by document order, then | 
 | 2742 |  * #xmlXPathTrailingSorted is called. | 
 | 2743 |  * | 
 | 2744 |  * Returns the nodes in @nodes1 that follow the first node in @nodes2 | 
 | 2745 |  *         in document order, @nodes1 if @nodes2 is NULL or empty or | 
 | 2746 |  *         an empty node-set if @nodes1 doesn't contain @nodes2 | 
 | 2747 |  */ | 
 | 2748 | xmlNodeSetPtr | 
 | 2749 | xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
 | 2750 |     if (xmlXPathNodeSetIsEmpty(nodes2)) | 
 | 2751 | 	return(nodes1); | 
 | 2752 |     if (xmlXPathNodeSetIsEmpty(nodes1)) | 
 | 2753 | 	return(xmlXPathNodeSetCreate(NULL)); | 
 | 2754 |     xmlXPathNodeSetSort(nodes1); | 
 | 2755 |     xmlXPathNodeSetSort(nodes2); | 
 | 2756 |     return(xmlXPathNodeTrailingSorted(nodes1, | 
 | 2757 | 				      xmlXPathNodeSetItem(nodes2, 0))); | 
 | 2758 | } | 
 | 2759 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2760 | /************************************************************************ | 
 | 2761 |  *									* | 
 | 2762 |  *		Routines to handle extra functions			* | 
 | 2763 |  *									* | 
 | 2764 |  ************************************************************************/ | 
 | 2765 |  | 
 | 2766 | /** | 
 | 2767 |  * xmlXPathRegisterFunc: | 
 | 2768 |  * @ctxt:  the XPath context | 
 | 2769 |  * @name:  the function name | 
 | 2770 |  * @f:  the function implementation or NULL | 
 | 2771 |  * | 
 | 2772 |  * Register a new function. If @f is NULL it unregisters the function | 
 | 2773 |  * | 
 | 2774 |  * Returns 0 in case of success, -1 in case of error | 
 | 2775 |  */ | 
 | 2776 | int		   | 
 | 2777 | xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, | 
 | 2778 | 		     xmlXPathFunction f) { | 
 | 2779 |     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); | 
 | 2780 | } | 
 | 2781 |  | 
 | 2782 | /** | 
 | 2783 |  * xmlXPathRegisterFuncNS: | 
 | 2784 |  * @ctxt:  the XPath context | 
 | 2785 |  * @name:  the function name | 
 | 2786 |  * @ns_uri:  the function namespace URI | 
 | 2787 |  * @f:  the function implementation or NULL | 
 | 2788 |  * | 
 | 2789 |  * Register a new function. If @f is NULL it unregisters the function | 
 | 2790 |  * | 
 | 2791 |  * Returns 0 in case of success, -1 in case of error | 
 | 2792 |  */ | 
 | 2793 | int | 
 | 2794 | xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, | 
 | 2795 | 		       const xmlChar *ns_uri, xmlXPathFunction f) { | 
 | 2796 |     if (ctxt == NULL) | 
 | 2797 | 	return(-1); | 
 | 2798 |     if (name == NULL) | 
 | 2799 | 	return(-1); | 
 | 2800 |  | 
 | 2801 |     if (ctxt->funcHash == NULL) | 
 | 2802 | 	ctxt->funcHash = xmlHashCreate(0); | 
 | 2803 |     if (ctxt->funcHash == NULL) | 
 | 2804 | 	return(-1); | 
| Daniel Veillard | 94394cd | 2003-10-29 17:07:51 +0000 | [diff] [blame] | 2805 |     if (f == NULL) | 
 | 2806 |         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2807 |     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); | 
 | 2808 | } | 
 | 2809 |  | 
 | 2810 | /** | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2811 |  * xmlXPathRegisterFuncLookup: | 
 | 2812 |  * @ctxt:  the XPath context | 
 | 2813 |  * @f:  the lookup function | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 2814 |  * @funcCtxt:  the lookup data | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2815 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 2816 |  * Registers an external mechanism to do function lookup. | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2817 |  */ | 
 | 2818 | void | 
 | 2819 | xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, | 
 | 2820 | 			    xmlXPathFuncLookupFunc f, | 
 | 2821 | 			    void *funcCtxt) { | 
 | 2822 |     if (ctxt == NULL) | 
 | 2823 | 	return; | 
| Daniel Veillard | 6ebf3c4 | 2004-08-22 13:11:39 +0000 | [diff] [blame] | 2824 |     ctxt->funcLookupFunc = f; | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2825 |     ctxt->funcLookupData = funcCtxt; | 
 | 2826 | } | 
 | 2827 |  | 
 | 2828 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2829 |  * xmlXPathFunctionLookup: | 
 | 2830 |  * @ctxt:  the XPath context | 
 | 2831 |  * @name:  the function name | 
 | 2832 |  * | 
 | 2833 |  * Search in the Function array of the context for the given | 
 | 2834 |  * function. | 
 | 2835 |  * | 
 | 2836 |  * Returns the xmlXPathFunction or NULL if not found | 
 | 2837 |  */ | 
 | 2838 | xmlXPathFunction | 
 | 2839 | xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2840 |     if (ctxt == NULL) | 
 | 2841 | 	return (NULL); | 
 | 2842 |  | 
 | 2843 |     if (ctxt->funcLookupFunc != NULL) { | 
 | 2844 | 	xmlXPathFunction ret; | 
| Daniel Veillard | 99e55eb | 2002-01-21 08:56:29 +0000 | [diff] [blame] | 2845 | 	xmlXPathFuncLookupFunc f; | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2846 |  | 
| Daniel Veillard | 6ebf3c4 | 2004-08-22 13:11:39 +0000 | [diff] [blame] | 2847 | 	f = ctxt->funcLookupFunc; | 
| Daniel Veillard | 963d2ae | 2002-01-20 22:08:18 +0000 | [diff] [blame] | 2848 | 	ret = f(ctxt->funcLookupData, name, NULL); | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2849 | 	if (ret != NULL) | 
 | 2850 | 	    return(ret); | 
 | 2851 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2852 |     return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); | 
 | 2853 | } | 
 | 2854 |  | 
 | 2855 | /** | 
 | 2856 |  * xmlXPathFunctionLookupNS: | 
 | 2857 |  * @ctxt:  the XPath context | 
 | 2858 |  * @name:  the function name | 
 | 2859 |  * @ns_uri:  the function namespace URI | 
 | 2860 |  * | 
 | 2861 |  * Search in the Function array of the context for the given | 
 | 2862 |  * function. | 
 | 2863 |  * | 
 | 2864 |  * Returns the xmlXPathFunction or NULL if not found | 
 | 2865 |  */ | 
 | 2866 | xmlXPathFunction | 
 | 2867 | xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, | 
 | 2868 | 			 const xmlChar *ns_uri) { | 
 | 2869 |     if (ctxt == NULL) | 
 | 2870 | 	return(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2871 |     if (name == NULL) | 
 | 2872 | 	return(NULL); | 
 | 2873 |  | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2874 |     if (ctxt->funcLookupFunc != NULL) { | 
 | 2875 | 	xmlXPathFunction ret; | 
| Daniel Veillard | 99e55eb | 2002-01-21 08:56:29 +0000 | [diff] [blame] | 2876 | 	xmlXPathFuncLookupFunc f; | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2877 |  | 
| Daniel Veillard | 6ebf3c4 | 2004-08-22 13:11:39 +0000 | [diff] [blame] | 2878 | 	f = ctxt->funcLookupFunc; | 
| Daniel Veillard | 963d2ae | 2002-01-20 22:08:18 +0000 | [diff] [blame] | 2879 | 	ret = f(ctxt->funcLookupData, name, ns_uri); | 
| Thomas Broyer | ba4ad32 | 2001-07-26 16:55:21 +0000 | [diff] [blame] | 2880 | 	if (ret != NULL) | 
 | 2881 | 	    return(ret); | 
 | 2882 |     } | 
 | 2883 |  | 
 | 2884 |     if (ctxt->funcHash == NULL) | 
 | 2885 | 	return(NULL); | 
 | 2886 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2887 |     return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri)); | 
 | 2888 | } | 
 | 2889 |  | 
 | 2890 | /** | 
 | 2891 |  * xmlXPathRegisteredFuncsCleanup: | 
 | 2892 |  * @ctxt:  the XPath context | 
 | 2893 |  * | 
 | 2894 |  * Cleanup the XPath context data associated to registered functions | 
 | 2895 |  */ | 
 | 2896 | void | 
 | 2897 | xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { | 
 | 2898 |     if (ctxt == NULL) | 
 | 2899 | 	return; | 
 | 2900 |  | 
 | 2901 |     xmlHashFree(ctxt->funcHash, NULL); | 
 | 2902 |     ctxt->funcHash = NULL; | 
 | 2903 | } | 
 | 2904 |  | 
 | 2905 | /************************************************************************ | 
 | 2906 |  *									* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 2907 |  *			Routines to handle Variables			* | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2908 |  *									* | 
 | 2909 |  ************************************************************************/ | 
 | 2910 |  | 
 | 2911 | /** | 
 | 2912 |  * xmlXPathRegisterVariable: | 
 | 2913 |  * @ctxt:  the XPath context | 
 | 2914 |  * @name:  the variable name | 
 | 2915 |  * @value:  the variable value or NULL | 
 | 2916 |  * | 
 | 2917 |  * Register a new variable value. If @value is NULL it unregisters | 
 | 2918 |  * the variable | 
 | 2919 |  * | 
 | 2920 |  * Returns 0 in case of success, -1 in case of error | 
 | 2921 |  */ | 
 | 2922 | int		   | 
 | 2923 | xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, | 
 | 2924 | 			 xmlXPathObjectPtr value) { | 
 | 2925 |     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); | 
 | 2926 | } | 
 | 2927 |  | 
 | 2928 | /** | 
 | 2929 |  * xmlXPathRegisterVariableNS: | 
 | 2930 |  * @ctxt:  the XPath context | 
 | 2931 |  * @name:  the variable name | 
 | 2932 |  * @ns_uri:  the variable namespace URI | 
 | 2933 |  * @value:  the variable value or NULL | 
 | 2934 |  * | 
 | 2935 |  * Register a new variable value. If @value is NULL it unregisters | 
 | 2936 |  * the variable | 
 | 2937 |  * | 
 | 2938 |  * Returns 0 in case of success, -1 in case of error | 
 | 2939 |  */ | 
 | 2940 | int | 
 | 2941 | xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, | 
 | 2942 | 			   const xmlChar *ns_uri, | 
 | 2943 | 			   xmlXPathObjectPtr value) { | 
 | 2944 |     if (ctxt == NULL) | 
 | 2945 | 	return(-1); | 
 | 2946 |     if (name == NULL) | 
 | 2947 | 	return(-1); | 
 | 2948 |  | 
 | 2949 |     if (ctxt->varHash == NULL) | 
 | 2950 | 	ctxt->varHash = xmlHashCreate(0); | 
 | 2951 |     if (ctxt->varHash == NULL) | 
 | 2952 | 	return(-1); | 
| Daniel Veillard | 94394cd | 2003-10-29 17:07:51 +0000 | [diff] [blame] | 2953 |     if (value == NULL) | 
 | 2954 |         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,  | 
 | 2955 | 	                           (xmlHashDeallocator)xmlXPathFreeObject)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2956 |     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, | 
 | 2957 | 			       (void *) value, | 
 | 2958 | 			       (xmlHashDeallocator)xmlXPathFreeObject)); | 
 | 2959 | } | 
 | 2960 |  | 
 | 2961 | /** | 
 | 2962 |  * xmlXPathRegisterVariableLookup: | 
 | 2963 |  * @ctxt:  the XPath context | 
 | 2964 |  * @f:  the lookup function | 
 | 2965 |  * @data:  the lookup data | 
 | 2966 |  * | 
 | 2967 |  * register an external mechanism to do variable lookup | 
 | 2968 |  */ | 
 | 2969 | void | 
 | 2970 | xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, | 
 | 2971 | 	 xmlXPathVariableLookupFunc f, void *data) { | 
 | 2972 |     if (ctxt == NULL) | 
 | 2973 | 	return; | 
| Daniel Veillard | 6ebf3c4 | 2004-08-22 13:11:39 +0000 | [diff] [blame] | 2974 |     ctxt->varLookupFunc = f; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2975 |     ctxt->varLookupData = data; | 
 | 2976 | } | 
 | 2977 |  | 
 | 2978 | /** | 
 | 2979 |  * xmlXPathVariableLookup: | 
 | 2980 |  * @ctxt:  the XPath context | 
 | 2981 |  * @name:  the variable name | 
 | 2982 |  * | 
 | 2983 |  * Search in the Variable array of the context for the given | 
 | 2984 |  * variable value. | 
 | 2985 |  * | 
| Daniel Veillard | 73c9c04 | 2001-07-05 20:02:54 +0000 | [diff] [blame] | 2986 |  * Returns a copy of the value or NULL if not found | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2987 |  */ | 
 | 2988 | xmlXPathObjectPtr | 
 | 2989 | xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { | 
 | 2990 |     if (ctxt == NULL) | 
 | 2991 | 	return(NULL); | 
 | 2992 |  | 
 | 2993 |     if (ctxt->varLookupFunc != NULL) { | 
 | 2994 | 	xmlXPathObjectPtr ret; | 
 | 2995 |  | 
 | 2996 | 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) | 
 | 2997 | 	        (ctxt->varLookupData, name, NULL); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 2998 | 	return(ret); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 2999 |     } | 
 | 3000 |     return(xmlXPathVariableLookupNS(ctxt, name, NULL)); | 
 | 3001 | } | 
 | 3002 |  | 
 | 3003 | /** | 
 | 3004 |  * xmlXPathVariableLookupNS: | 
 | 3005 |  * @ctxt:  the XPath context | 
 | 3006 |  * @name:  the variable name | 
 | 3007 |  * @ns_uri:  the variable namespace URI | 
 | 3008 |  * | 
 | 3009 |  * Search in the Variable array of the context for the given | 
| Daniel Veillard | 73c9c04 | 2001-07-05 20:02:54 +0000 | [diff] [blame] | 3010 |  * variable value.  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3011 |  * | 
| Daniel Veillard | 73c9c04 | 2001-07-05 20:02:54 +0000 | [diff] [blame] | 3012 |  * Returns the a copy of the value or NULL if not found | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3013 |  */ | 
 | 3014 | xmlXPathObjectPtr | 
 | 3015 | xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, | 
 | 3016 | 			 const xmlChar *ns_uri) { | 
 | 3017 |     if (ctxt == NULL) | 
 | 3018 | 	return(NULL); | 
 | 3019 |  | 
 | 3020 |     if (ctxt->varLookupFunc != NULL) { | 
 | 3021 | 	xmlXPathObjectPtr ret; | 
 | 3022 |  | 
 | 3023 | 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) | 
 | 3024 | 	        (ctxt->varLookupData, name, ns_uri); | 
 | 3025 | 	if (ret != NULL) return(ret); | 
 | 3026 |     } | 
 | 3027 |  | 
 | 3028 |     if (ctxt->varHash == NULL) | 
 | 3029 | 	return(NULL); | 
 | 3030 |     if (name == NULL) | 
 | 3031 | 	return(NULL); | 
 | 3032 |  | 
| Daniel Veillard | 8c357d5 | 2001-07-03 23:43:33 +0000 | [diff] [blame] | 3033 |     return(xmlXPathObjectCopy((xmlXPathObjectPtr) | 
 | 3034 | 		xmlHashLookup2(ctxt->varHash, name, ns_uri))); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3035 | } | 
 | 3036 |  | 
 | 3037 | /** | 
 | 3038 |  * xmlXPathRegisteredVariablesCleanup: | 
 | 3039 |  * @ctxt:  the XPath context | 
 | 3040 |  * | 
 | 3041 |  * Cleanup the XPath context data associated to registered variables | 
 | 3042 |  */ | 
 | 3043 | void | 
 | 3044 | xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { | 
 | 3045 |     if (ctxt == NULL) | 
 | 3046 | 	return; | 
 | 3047 |  | 
| Daniel Veillard | 76d66f4 | 2001-05-16 21:05:17 +0000 | [diff] [blame] | 3048 |     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3049 |     ctxt->varHash = NULL; | 
 | 3050 | } | 
 | 3051 |  | 
 | 3052 | /** | 
 | 3053 |  * xmlXPathRegisterNs: | 
 | 3054 |  * @ctxt:  the XPath context | 
 | 3055 |  * @prefix:  the namespace prefix | 
 | 3056 |  * @ns_uri:  the namespace name | 
 | 3057 |  * | 
 | 3058 |  * Register a new namespace. If @ns_uri is NULL it unregisters | 
 | 3059 |  * the namespace | 
 | 3060 |  * | 
 | 3061 |  * Returns 0 in case of success, -1 in case of error | 
 | 3062 |  */ | 
 | 3063 | int | 
 | 3064 | xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, | 
 | 3065 | 			   const xmlChar *ns_uri) { | 
 | 3066 |     if (ctxt == NULL) | 
 | 3067 | 	return(-1); | 
 | 3068 |     if (prefix == NULL) | 
 | 3069 | 	return(-1); | 
 | 3070 |  | 
 | 3071 |     if (ctxt->nsHash == NULL) | 
 | 3072 | 	ctxt->nsHash = xmlHashCreate(10); | 
 | 3073 |     if (ctxt->nsHash == NULL) | 
 | 3074 | 	return(-1); | 
| Daniel Veillard | e991fe9 | 2003-10-29 11:18:37 +0000 | [diff] [blame] | 3075 |     if (ns_uri == NULL) | 
| Daniel Veillard | 94394cd | 2003-10-29 17:07:51 +0000 | [diff] [blame] | 3076 |         return(xmlHashRemoveEntry(ctxt->nsHash, prefix, | 
| Daniel Veillard | e991fe9 | 2003-10-29 11:18:37 +0000 | [diff] [blame] | 3077 | 	                          (xmlHashDeallocator)xmlFree)); | 
| Daniel Veillard | 42766c0 | 2002-08-22 20:52:17 +0000 | [diff] [blame] | 3078 |     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3079 | 			      (xmlHashDeallocator)xmlFree)); | 
 | 3080 | } | 
 | 3081 |  | 
 | 3082 | /** | 
 | 3083 |  * xmlXPathNsLookup: | 
 | 3084 |  * @ctxt:  the XPath context | 
 | 3085 |  * @prefix:  the namespace prefix value | 
 | 3086 |  * | 
 | 3087 |  * Search in the namespace declaration array of the context for the given | 
 | 3088 |  * namespace name associated to the given prefix | 
 | 3089 |  * | 
 | 3090 |  * Returns the value or NULL if not found | 
 | 3091 |  */ | 
 | 3092 | const xmlChar * | 
 | 3093 | xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { | 
 | 3094 |     if (ctxt == NULL) | 
 | 3095 | 	return(NULL); | 
 | 3096 |     if (prefix == NULL) | 
 | 3097 | 	return(NULL); | 
 | 3098 |  | 
 | 3099 | #ifdef XML_XML_NAMESPACE | 
 | 3100 |     if (xmlStrEqual(prefix, (const xmlChar *) "xml")) | 
 | 3101 | 	return(XML_XML_NAMESPACE); | 
 | 3102 | #endif | 
 | 3103 |  | 
| Daniel Veillard | c8f620b | 2001-04-30 20:31:33 +0000 | [diff] [blame] | 3104 |     if (ctxt->namespaces != NULL) { | 
 | 3105 | 	int i; | 
 | 3106 |  | 
 | 3107 | 	for (i = 0;i < ctxt->nsNr;i++) { | 
 | 3108 | 	    if ((ctxt->namespaces[i] != NULL) && | 
 | 3109 | 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) | 
 | 3110 | 		return(ctxt->namespaces[i]->href); | 
 | 3111 | 	} | 
 | 3112 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3113 |  | 
 | 3114 |     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); | 
 | 3115 | } | 
 | 3116 |  | 
 | 3117 | /** | 
| Daniel Veillard | 5e2dace | 2001-07-18 19:30:27 +0000 | [diff] [blame] | 3118 |  * xmlXPathRegisteredNsCleanup: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3119 |  * @ctxt:  the XPath context | 
 | 3120 |  * | 
 | 3121 |  * Cleanup the XPath context data associated to registered variables | 
 | 3122 |  */ | 
 | 3123 | void | 
 | 3124 | xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { | 
 | 3125 |     if (ctxt == NULL) | 
 | 3126 | 	return; | 
 | 3127 |  | 
| Daniel Veillard | 42766c0 | 2002-08-22 20:52:17 +0000 | [diff] [blame] | 3128 |     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3129 |     ctxt->nsHash = NULL; | 
 | 3130 | } | 
 | 3131 |  | 
 | 3132 | /************************************************************************ | 
 | 3133 |  *									* | 
 | 3134 |  *			Routines to handle Values			* | 
 | 3135 |  *									* | 
 | 3136 |  ************************************************************************/ | 
 | 3137 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 3138 | /* Allocations are terrible, one needs to optimize all this !!! */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3139 |  | 
 | 3140 | /** | 
 | 3141 |  * xmlXPathNewFloat: | 
 | 3142 |  * @val:  the double value | 
 | 3143 |  * | 
 | 3144 |  * Create a new xmlXPathObjectPtr of type double and of value @val | 
 | 3145 |  * | 
 | 3146 |  * Returns the newly created object. | 
 | 3147 |  */ | 
 | 3148 | xmlXPathObjectPtr | 
 | 3149 | xmlXPathNewFloat(double val) { | 
 | 3150 |     xmlXPathObjectPtr ret; | 
 | 3151 |  | 
 | 3152 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 3153 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3154 |         xmlXPathErrMemory(NULL, "creating float object\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3155 | 	return(NULL); | 
 | 3156 |     } | 
 | 3157 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 3158 |     ret->type = XPATH_NUMBER; | 
 | 3159 |     ret->floatval = val; | 
 | 3160 |     return(ret); | 
 | 3161 | } | 
 | 3162 |  | 
 | 3163 | /** | 
 | 3164 |  * xmlXPathNewBoolean: | 
 | 3165 |  * @val:  the boolean value | 
 | 3166 |  * | 
 | 3167 |  * Create a new xmlXPathObjectPtr of type boolean and of value @val | 
 | 3168 |  * | 
 | 3169 |  * Returns the newly created object. | 
 | 3170 |  */ | 
 | 3171 | xmlXPathObjectPtr | 
 | 3172 | xmlXPathNewBoolean(int val) { | 
 | 3173 |     xmlXPathObjectPtr ret; | 
 | 3174 |  | 
 | 3175 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 3176 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3177 |         xmlXPathErrMemory(NULL, "creating boolean object\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3178 | 	return(NULL); | 
 | 3179 |     } | 
 | 3180 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 3181 |     ret->type = XPATH_BOOLEAN; | 
 | 3182 |     ret->boolval = (val != 0); | 
 | 3183 |     return(ret); | 
 | 3184 | } | 
 | 3185 |  | 
 | 3186 | /** | 
 | 3187 |  * xmlXPathNewString: | 
 | 3188 |  * @val:  the xmlChar * value | 
 | 3189 |  * | 
 | 3190 |  * Create a new xmlXPathObjectPtr of type string and of value @val | 
 | 3191 |  * | 
 | 3192 |  * Returns the newly created object. | 
 | 3193 |  */ | 
 | 3194 | xmlXPathObjectPtr | 
 | 3195 | xmlXPathNewString(const xmlChar *val) { | 
 | 3196 |     xmlXPathObjectPtr ret; | 
 | 3197 |  | 
 | 3198 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 3199 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3200 |         xmlXPathErrMemory(NULL, "creating string object\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3201 | 	return(NULL); | 
 | 3202 |     } | 
 | 3203 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 3204 |     ret->type = XPATH_STRING; | 
 | 3205 |     if (val != NULL) | 
 | 3206 | 	ret->stringval = xmlStrdup(val); | 
 | 3207 |     else | 
 | 3208 | 	ret->stringval = xmlStrdup((const xmlChar *)""); | 
 | 3209 |     return(ret); | 
 | 3210 | } | 
 | 3211 |  | 
 | 3212 | /** | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3213 |  * xmlXPathWrapString: | 
 | 3214 |  * @val:  the xmlChar * value | 
 | 3215 |  * | 
 | 3216 |  * Wraps the @val string into an XPath object. | 
 | 3217 |  * | 
 | 3218 |  * Returns the newly created object. | 
 | 3219 |  */ | 
 | 3220 | xmlXPathObjectPtr | 
 | 3221 | xmlXPathWrapString (xmlChar *val) { | 
 | 3222 |     xmlXPathObjectPtr ret; | 
 | 3223 |  | 
 | 3224 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 3225 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3226 |         xmlXPathErrMemory(NULL, "creating string object\n"); | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3227 | 	return(NULL); | 
 | 3228 |     } | 
 | 3229 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 3230 |     ret->type = XPATH_STRING; | 
 | 3231 |     ret->stringval = val; | 
 | 3232 |     return(ret); | 
 | 3233 | } | 
 | 3234 |  | 
 | 3235 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3236 |  * xmlXPathNewCString: | 
 | 3237 |  * @val:  the char * value | 
 | 3238 |  * | 
 | 3239 |  * Create a new xmlXPathObjectPtr of type string and of value @val | 
 | 3240 |  * | 
 | 3241 |  * Returns the newly created object. | 
 | 3242 |  */ | 
 | 3243 | xmlXPathObjectPtr | 
 | 3244 | xmlXPathNewCString(const char *val) { | 
 | 3245 |     xmlXPathObjectPtr ret; | 
 | 3246 |  | 
 | 3247 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 3248 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3249 |         xmlXPathErrMemory(NULL, "creating string object\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3250 | 	return(NULL); | 
 | 3251 |     } | 
 | 3252 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 3253 |     ret->type = XPATH_STRING; | 
 | 3254 |     ret->stringval = xmlStrdup(BAD_CAST val); | 
 | 3255 |     return(ret); | 
 | 3256 | } | 
 | 3257 |  | 
 | 3258 | /** | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3259 |  * xmlXPathWrapCString: | 
 | 3260 |  * @val:  the char * value | 
 | 3261 |  * | 
 | 3262 |  * Wraps a string into an XPath object. | 
 | 3263 |  * | 
 | 3264 |  * Returns the newly created object. | 
 | 3265 |  */ | 
 | 3266 | xmlXPathObjectPtr | 
 | 3267 | xmlXPathWrapCString (char * val) { | 
 | 3268 |     return(xmlXPathWrapString((xmlChar *)(val))); | 
 | 3269 | } | 
 | 3270 |  | 
 | 3271 | /** | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 3272 |  * xmlXPathWrapExternal: | 
 | 3273 |  * @val:  the user data | 
 | 3274 |  * | 
 | 3275 |  * Wraps the @val data into an XPath object. | 
 | 3276 |  * | 
 | 3277 |  * Returns the newly created object. | 
 | 3278 |  */ | 
 | 3279 | xmlXPathObjectPtr | 
 | 3280 | xmlXPathWrapExternal (void *val) { | 
 | 3281 |     xmlXPathObjectPtr ret; | 
 | 3282 |  | 
 | 3283 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 3284 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3285 |         xmlXPathErrMemory(NULL, "creating user object\n"); | 
| Thomas Broyer | f06a3d8 | 2001-07-16 04:52:57 +0000 | [diff] [blame] | 3286 | 	return(NULL); | 
 | 3287 |     } | 
 | 3288 |     memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); | 
 | 3289 |     ret->type = XPATH_USERS; | 
 | 3290 |     ret->user = val; | 
 | 3291 |     return(ret); | 
 | 3292 | } | 
 | 3293 |  | 
 | 3294 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3295 |  * xmlXPathObjectCopy: | 
 | 3296 |  * @val:  the original object | 
 | 3297 |  * | 
 | 3298 |  * allocate a new copy of a given object | 
 | 3299 |  * | 
 | 3300 |  * Returns the newly created object. | 
 | 3301 |  */ | 
 | 3302 | xmlXPathObjectPtr | 
 | 3303 | xmlXPathObjectCopy(xmlXPathObjectPtr val) { | 
 | 3304 |     xmlXPathObjectPtr ret; | 
 | 3305 |  | 
 | 3306 |     if (val == NULL) | 
 | 3307 | 	return(NULL); | 
 | 3308 |  | 
 | 3309 |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); | 
 | 3310 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3311 |         xmlXPathErrMemory(NULL, "copying object\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3312 | 	return(NULL); | 
 | 3313 |     } | 
 | 3314 |     memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); | 
 | 3315 |     switch (val->type) { | 
 | 3316 | 	case XPATH_BOOLEAN: | 
 | 3317 | 	case XPATH_NUMBER: | 
 | 3318 | 	case XPATH_POINT: | 
 | 3319 | 	case XPATH_RANGE: | 
 | 3320 | 	    break; | 
 | 3321 | 	case XPATH_STRING: | 
 | 3322 | 	    ret->stringval = xmlStrdup(val->stringval); | 
 | 3323 | 	    break; | 
 | 3324 | 	case XPATH_XSLT_TREE: | 
| William M. Brack | e9449c5 | 2004-07-11 14:41:20 +0000 | [diff] [blame] | 3325 | #if 0 | 
 | 3326 | /* | 
 | 3327 |   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that | 
 | 3328 |   this previous handling is no longer correct, and can cause some serious | 
 | 3329 |   problems (ref. bug 145547) | 
 | 3330 | */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3331 | 	    if ((val->nodesetval != NULL) && | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3332 | 		(val->nodesetval->nodeTab != NULL)) { | 
| Daniel Veillard | 9adc046 | 2003-03-24 18:39:54 +0000 | [diff] [blame] | 3333 | 		xmlNodePtr cur, tmp; | 
 | 3334 | 		xmlDocPtr top; | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 3335 |  | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3336 | 		ret->boolval = 1; | 
| Daniel Veillard | 9adc046 | 2003-03-24 18:39:54 +0000 | [diff] [blame] | 3337 | 		top =  xmlNewDoc(NULL); | 
 | 3338 | 		top->name = (char *) | 
 | 3339 | 		    xmlStrdup(val->nodesetval->nodeTab[0]->name); | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 3340 | 		ret->user = top; | 
 | 3341 | 		if (top != NULL) { | 
| Daniel Veillard | 9adc046 | 2003-03-24 18:39:54 +0000 | [diff] [blame] | 3342 | 		    top->doc = top; | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 3343 | 		    cur = val->nodesetval->nodeTab[0]->children; | 
 | 3344 | 		    while (cur != NULL) { | 
| Daniel Veillard | 9adc046 | 2003-03-24 18:39:54 +0000 | [diff] [blame] | 3345 | 			tmp = xmlDocCopyNode(cur, top, 1); | 
 | 3346 | 			xmlAddChild((xmlNodePtr) top, tmp); | 
| Daniel Veillard | ef0b450 | 2003-03-24 13:57:34 +0000 | [diff] [blame] | 3347 | 			cur = cur->next; | 
 | 3348 | 		    } | 
 | 3349 | 		} | 
| William M. Brack | e9449c5 | 2004-07-11 14:41:20 +0000 | [diff] [blame] | 3350 |  | 
| Daniel Veillard | 9adc046 | 2003-03-24 18:39:54 +0000 | [diff] [blame] | 3351 | 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3352 | 	    } else | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3353 | 		ret->nodesetval = xmlXPathNodeSetCreate(NULL); | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3354 | 	    /* Deallocate the copied tree value */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3355 | 	    break; | 
| William M. Brack | e9449c5 | 2004-07-11 14:41:20 +0000 | [diff] [blame] | 3356 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3357 | 	case XPATH_NODESET: | 
 | 3358 | 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3359 | 	    /* Do not deallocate the copied tree value */ | 
 | 3360 | 	    ret->boolval = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3361 | 	    break; | 
 | 3362 | 	case XPATH_LOCATIONSET: | 
 | 3363 | #ifdef LIBXML_XPTR_ENABLED | 
 | 3364 | 	{ | 
 | 3365 | 	    xmlLocationSetPtr loc = val->user; | 
 | 3366 | 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); | 
 | 3367 | 	    break; | 
 | 3368 | 	} | 
 | 3369 | #endif | 
| Thomas Broyer | 47334c0 | 2001-10-07 16:41:52 +0000 | [diff] [blame] | 3370 |         case XPATH_USERS: | 
 | 3371 | 	    ret->user = val->user; | 
 | 3372 | 	    break;  | 
 | 3373 |         case XPATH_UNDEFINED: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3374 | 	    xmlGenericError(xmlGenericErrorContext, | 
 | 3375 | 		    "xmlXPathObjectCopy: unsupported type %d\n", | 
 | 3376 | 		    val->type); | 
 | 3377 | 	    break; | 
 | 3378 |     } | 
 | 3379 |     return(ret); | 
 | 3380 | } | 
 | 3381 |  | 
 | 3382 | /** | 
 | 3383 |  * xmlXPathFreeObject: | 
 | 3384 |  * @obj:  the object to free | 
 | 3385 |  * | 
 | 3386 |  * Free up an xmlXPathObjectPtr object. | 
 | 3387 |  */ | 
 | 3388 | void | 
 | 3389 | xmlXPathFreeObject(xmlXPathObjectPtr obj) { | 
 | 3390 |     if (obj == NULL) return; | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3391 |     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { | 
| Daniel Veillard | 7785171 | 2001-02-27 21:54:07 +0000 | [diff] [blame] | 3392 | 	if (obj->boolval) { | 
| William M. Brack | e9449c5 | 2004-07-11 14:41:20 +0000 | [diff] [blame] | 3393 | #if 0 | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3394 | 	    if (obj->user != NULL) { | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 3395 |                 xmlXPathFreeNodeSet(obj->nodesetval); | 
| Daniel Veillard | 38bf6f0 | 2002-03-16 22:03:31 +0000 | [diff] [blame] | 3396 | 		xmlFreeNodeList((xmlNodePtr) obj->user); | 
| William M. Brack | e9449c5 | 2004-07-11 14:41:20 +0000 | [diff] [blame] | 3397 | 	    } else | 
 | 3398 | #endif | 
 | 3399 | 	    if (obj->nodesetval != NULL) | 
| Daniel Veillard | 7785171 | 2001-02-27 21:54:07 +0000 | [diff] [blame] | 3400 | 		xmlXPathFreeValueTree(obj->nodesetval); | 
 | 3401 | 	} else { | 
 | 3402 | 	    if (obj->nodesetval != NULL) | 
 | 3403 | 		xmlXPathFreeNodeSet(obj->nodesetval); | 
 | 3404 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3405 | #ifdef LIBXML_XPTR_ENABLED | 
 | 3406 |     } else if (obj->type == XPATH_LOCATIONSET) { | 
 | 3407 | 	if (obj->user != NULL) | 
 | 3408 | 	    xmlXPtrFreeLocationSet(obj->user); | 
 | 3409 | #endif | 
 | 3410 |     } else if (obj->type == XPATH_STRING) { | 
 | 3411 | 	if (obj->stringval != NULL) | 
 | 3412 | 	    xmlFree(obj->stringval); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3413 |     } | 
 | 3414 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3415 |     xmlFree(obj); | 
 | 3416 | } | 
 | 3417 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3418 |  | 
 | 3419 | /************************************************************************ | 
 | 3420 |  *									* | 
 | 3421 |  *			Type Casting Routines				* | 
 | 3422 |  *									* | 
 | 3423 |  ************************************************************************/ | 
 | 3424 |  | 
 | 3425 | /** | 
 | 3426 |  * xmlXPathCastBooleanToString: | 
 | 3427 |  * @val:  a boolean | 
 | 3428 |  * | 
 | 3429 |  * Converts a boolean to its string value. | 
 | 3430 |  * | 
 | 3431 |  * Returns a newly allocated string. | 
 | 3432 |  */ | 
 | 3433 | xmlChar * | 
 | 3434 | xmlXPathCastBooleanToString (int val) { | 
 | 3435 |     xmlChar *ret; | 
 | 3436 |     if (val) | 
 | 3437 | 	ret = xmlStrdup((const xmlChar *) "true"); | 
 | 3438 |     else | 
 | 3439 | 	ret = xmlStrdup((const xmlChar *) "false"); | 
 | 3440 |     return(ret); | 
 | 3441 | } | 
 | 3442 |  | 
 | 3443 | /** | 
 | 3444 |  * xmlXPathCastNumberToString: | 
 | 3445 |  * @val:  a number | 
 | 3446 |  * | 
 | 3447 |  * Converts a number to its string value. | 
 | 3448 |  * | 
 | 3449 |  * Returns a newly allocated string. | 
 | 3450 |  */ | 
 | 3451 | xmlChar * | 
 | 3452 | xmlXPathCastNumberToString (double val) { | 
 | 3453 |     xmlChar *ret; | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 3454 |     switch (xmlXPathIsInf(val)) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3455 |     case 1: | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 3456 | 	ret = xmlStrdup((const xmlChar *) "Infinity"); | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3457 | 	break; | 
 | 3458 |     case -1: | 
 | 3459 | 	ret = xmlStrdup((const xmlChar *) "-Infinity"); | 
 | 3460 | 	break; | 
 | 3461 |     default: | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 3462 | 	if (xmlXPathIsNaN(val)) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3463 | 	    ret = xmlStrdup((const xmlChar *) "NaN"); | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 3464 | 	} else if (val == 0 && xmlXPathGetSign(val) != 0) { | 
 | 3465 | 	    ret = xmlStrdup((const xmlChar *) "0"); | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3466 | 	} else { | 
 | 3467 | 	    /* could be improved */ | 
 | 3468 | 	    char buf[100]; | 
 | 3469 | 	    xmlXPathFormatNumber(val, buf, 100); | 
 | 3470 | 	    ret = xmlStrdup((const xmlChar *) buf); | 
 | 3471 | 	} | 
 | 3472 |     } | 
 | 3473 |     return(ret); | 
 | 3474 | } | 
 | 3475 |  | 
 | 3476 | /** | 
 | 3477 |  * xmlXPathCastNodeToString: | 
 | 3478 |  * @node:  a node | 
 | 3479 |  * | 
 | 3480 |  * Converts a node to its string value. | 
 | 3481 |  * | 
 | 3482 |  * Returns a newly allocated string. | 
 | 3483 |  */ | 
 | 3484 | xmlChar * | 
 | 3485 | xmlXPathCastNodeToString (xmlNodePtr node) { | 
 | 3486 |     return(xmlNodeGetContent(node)); | 
 | 3487 | } | 
 | 3488 |  | 
 | 3489 | /** | 
 | 3490 |  * xmlXPathCastNodeSetToString: | 
 | 3491 |  * @ns:  a node-set | 
 | 3492 |  * | 
 | 3493 |  * Converts a node-set to its string value. | 
 | 3494 |  * | 
 | 3495 |  * Returns a newly allocated string. | 
 | 3496 |  */ | 
 | 3497 | xmlChar * | 
 | 3498 | xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { | 
 | 3499 |     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) | 
 | 3500 | 	return(xmlStrdup((const xmlChar *) "")); | 
 | 3501 |  | 
 | 3502 |     xmlXPathNodeSetSort(ns); | 
 | 3503 |     return(xmlXPathCastNodeToString(ns->nodeTab[0])); | 
 | 3504 | } | 
 | 3505 |  | 
 | 3506 | /** | 
 | 3507 |  * xmlXPathCastToString: | 
 | 3508 |  * @val:  an XPath object | 
 | 3509 |  * | 
 | 3510 |  * Converts an existing object to its string() equivalent | 
 | 3511 |  * | 
 | 3512 |  * Returns the string value of the object, NULL in case of error. | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 3513 |  *         A new string is allocated only if needed (@val isn't a | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3514 |  *         string object). | 
 | 3515 |  */ | 
 | 3516 | xmlChar * | 
 | 3517 | xmlXPathCastToString(xmlXPathObjectPtr val) { | 
 | 3518 |     xmlChar *ret = NULL; | 
 | 3519 |  | 
 | 3520 |     if (val == NULL) | 
 | 3521 | 	return(xmlStrdup((const xmlChar *) "")); | 
 | 3522 |     switch (val->type) { | 
 | 3523 | 	case XPATH_UNDEFINED: | 
 | 3524 | #ifdef DEBUG_EXPR | 
 | 3525 | 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); | 
 | 3526 | #endif | 
 | 3527 | 	    ret = xmlStrdup((const xmlChar *) ""); | 
 | 3528 | 	    break; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3529 |         case XPATH_NODESET: | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 3530 |         case XPATH_XSLT_TREE: | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3531 | 	    ret = xmlXPathCastNodeSetToString(val->nodesetval); | 
 | 3532 | 	    break; | 
 | 3533 | 	case XPATH_STRING: | 
| Daniel Veillard | 4e2df54 | 2002-03-22 12:23:14 +0000 | [diff] [blame] | 3534 | 	    return(xmlStrdup(val->stringval)); | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3535 |         case XPATH_BOOLEAN: | 
 | 3536 | 	    ret = xmlXPathCastBooleanToString(val->boolval); | 
 | 3537 | 	    break; | 
 | 3538 | 	case XPATH_NUMBER: { | 
 | 3539 | 	    ret = xmlXPathCastNumberToString(val->floatval); | 
 | 3540 | 	    break; | 
 | 3541 | 	} | 
 | 3542 | 	case XPATH_USERS: | 
 | 3543 | 	case XPATH_POINT: | 
 | 3544 | 	case XPATH_RANGE: | 
 | 3545 | 	case XPATH_LOCATIONSET: | 
 | 3546 | 	    TODO | 
 | 3547 | 	    ret = xmlStrdup((const xmlChar *) ""); | 
 | 3548 | 	    break; | 
 | 3549 |     } | 
 | 3550 |     return(ret); | 
 | 3551 | } | 
 | 3552 |  | 
 | 3553 | /** | 
 | 3554 |  * xmlXPathConvertString: | 
 | 3555 |  * @val:  an XPath object | 
 | 3556 |  * | 
 | 3557 |  * Converts an existing object to its string() equivalent | 
 | 3558 |  * | 
 | 3559 |  * Returns the new object, the old one is freed (or the operation | 
 | 3560 |  *         is done directly on @val) | 
 | 3561 |  */ | 
 | 3562 | xmlXPathObjectPtr | 
 | 3563 | xmlXPathConvertString(xmlXPathObjectPtr val) { | 
 | 3564 |     xmlChar *res = NULL; | 
 | 3565 |  | 
 | 3566 |     if (val == NULL) | 
 | 3567 | 	return(xmlXPathNewCString("")); | 
 | 3568 |  | 
 | 3569 |     switch (val->type) { | 
 | 3570 |     case XPATH_UNDEFINED: | 
 | 3571 | #ifdef DEBUG_EXPR | 
 | 3572 | 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); | 
 | 3573 | #endif | 
 | 3574 | 	break; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3575 |     case XPATH_NODESET: | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 3576 |     case XPATH_XSLT_TREE: | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3577 | 	res = xmlXPathCastNodeSetToString(val->nodesetval); | 
 | 3578 | 	break; | 
 | 3579 |     case XPATH_STRING: | 
 | 3580 | 	return(val); | 
 | 3581 |     case XPATH_BOOLEAN: | 
 | 3582 | 	res = xmlXPathCastBooleanToString(val->boolval); | 
 | 3583 | 	break; | 
 | 3584 |     case XPATH_NUMBER: | 
 | 3585 | 	res = xmlXPathCastNumberToString(val->floatval); | 
 | 3586 | 	break; | 
 | 3587 |     case XPATH_USERS: | 
 | 3588 |     case XPATH_POINT: | 
 | 3589 |     case XPATH_RANGE: | 
 | 3590 |     case XPATH_LOCATIONSET: | 
 | 3591 | 	TODO; | 
 | 3592 | 	break; | 
 | 3593 |     } | 
 | 3594 |     xmlXPathFreeObject(val); | 
 | 3595 |     if (res == NULL) | 
 | 3596 | 	return(xmlXPathNewCString("")); | 
 | 3597 |     return(xmlXPathWrapString(res)); | 
 | 3598 | } | 
 | 3599 |  | 
 | 3600 | /** | 
 | 3601 |  * xmlXPathCastBooleanToNumber: | 
 | 3602 |  * @val:  a boolean | 
 | 3603 |  * | 
 | 3604 |  * Converts a boolean to its number value | 
 | 3605 |  * | 
 | 3606 |  * Returns the number value | 
 | 3607 |  */ | 
 | 3608 | double | 
 | 3609 | xmlXPathCastBooleanToNumber(int val) { | 
 | 3610 |     if (val) | 
 | 3611 | 	return(1.0); | 
 | 3612 |     return(0.0); | 
 | 3613 | } | 
 | 3614 |  | 
 | 3615 | /** | 
 | 3616 |  * xmlXPathCastStringToNumber: | 
 | 3617 |  * @val:  a string | 
 | 3618 |  * | 
 | 3619 |  * Converts a string to its number value | 
 | 3620 |  * | 
 | 3621 |  * Returns the number value | 
 | 3622 |  */ | 
 | 3623 | double | 
 | 3624 | xmlXPathCastStringToNumber(const xmlChar * val) { | 
 | 3625 |     return(xmlXPathStringEvalNumber(val)); | 
 | 3626 | } | 
 | 3627 |  | 
 | 3628 | /** | 
 | 3629 |  * xmlXPathCastNodeToNumber: | 
 | 3630 |  * @node:  a node | 
 | 3631 |  * | 
 | 3632 |  * Converts a node to its number value | 
 | 3633 |  * | 
 | 3634 |  * Returns the number value | 
 | 3635 |  */ | 
 | 3636 | double | 
 | 3637 | xmlXPathCastNodeToNumber (xmlNodePtr node) { | 
 | 3638 |     xmlChar *strval; | 
 | 3639 |     double ret; | 
 | 3640 |  | 
 | 3641 |     if (node == NULL) | 
 | 3642 | 	return(xmlXPathNAN); | 
 | 3643 |     strval = xmlXPathCastNodeToString(node); | 
 | 3644 |     if (strval == NULL) | 
 | 3645 | 	return(xmlXPathNAN); | 
 | 3646 |     ret = xmlXPathCastStringToNumber(strval); | 
 | 3647 |     xmlFree(strval); | 
 | 3648 |  | 
 | 3649 |     return(ret); | 
 | 3650 | } | 
 | 3651 |  | 
 | 3652 | /** | 
 | 3653 |  * xmlXPathCastNodeSetToNumber: | 
 | 3654 |  * @ns:  a node-set | 
 | 3655 |  * | 
 | 3656 |  * Converts a node-set to its number value | 
 | 3657 |  * | 
 | 3658 |  * Returns the number value | 
 | 3659 |  */ | 
 | 3660 | double | 
 | 3661 | xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { | 
 | 3662 |     xmlChar *str; | 
 | 3663 |     double ret; | 
 | 3664 |  | 
 | 3665 |     if (ns == NULL) | 
 | 3666 | 	return(xmlXPathNAN); | 
 | 3667 |     str = xmlXPathCastNodeSetToString(ns); | 
 | 3668 |     ret = xmlXPathCastStringToNumber(str); | 
 | 3669 |     xmlFree(str); | 
 | 3670 |     return(ret); | 
 | 3671 | } | 
 | 3672 |  | 
 | 3673 | /** | 
 | 3674 |  * xmlXPathCastToNumber: | 
 | 3675 |  * @val:  an XPath object | 
 | 3676 |  * | 
 | 3677 |  * Converts an XPath object to its number value | 
 | 3678 |  * | 
 | 3679 |  * Returns the number value | 
 | 3680 |  */ | 
 | 3681 | double | 
 | 3682 | xmlXPathCastToNumber(xmlXPathObjectPtr val) { | 
 | 3683 |     double ret = 0.0; | 
 | 3684 |  | 
 | 3685 |     if (val == NULL) | 
 | 3686 | 	return(xmlXPathNAN); | 
 | 3687 |     switch (val->type) { | 
 | 3688 |     case XPATH_UNDEFINED: | 
 | 3689 | #ifdef DEGUB_EXPR | 
 | 3690 | 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); | 
 | 3691 | #endif | 
 | 3692 | 	ret = xmlXPathNAN; | 
 | 3693 | 	break; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3694 |     case XPATH_NODESET: | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 3695 |     case XPATH_XSLT_TREE: | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3696 | 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval); | 
 | 3697 | 	break; | 
 | 3698 |     case XPATH_STRING: | 
 | 3699 | 	ret = xmlXPathCastStringToNumber(val->stringval); | 
 | 3700 | 	break; | 
 | 3701 |     case XPATH_NUMBER: | 
 | 3702 | 	ret = val->floatval; | 
 | 3703 | 	break; | 
 | 3704 |     case XPATH_BOOLEAN: | 
 | 3705 | 	ret = xmlXPathCastBooleanToNumber(val->boolval); | 
 | 3706 | 	break; | 
 | 3707 |     case XPATH_USERS: | 
 | 3708 |     case XPATH_POINT: | 
 | 3709 |     case XPATH_RANGE: | 
 | 3710 |     case XPATH_LOCATIONSET: | 
 | 3711 | 	TODO; | 
 | 3712 | 	ret = xmlXPathNAN; | 
 | 3713 | 	break; | 
 | 3714 |     } | 
 | 3715 |     return(ret); | 
 | 3716 | } | 
 | 3717 |  | 
 | 3718 | /** | 
 | 3719 |  * xmlXPathConvertNumber: | 
 | 3720 |  * @val:  an XPath object | 
 | 3721 |  * | 
 | 3722 |  * Converts an existing object to its number() equivalent | 
 | 3723 |  * | 
 | 3724 |  * Returns the new object, the old one is freed (or the operation | 
 | 3725 |  *         is done directly on @val) | 
 | 3726 |  */ | 
 | 3727 | xmlXPathObjectPtr | 
 | 3728 | xmlXPathConvertNumber(xmlXPathObjectPtr val) { | 
 | 3729 |     xmlXPathObjectPtr ret; | 
 | 3730 |  | 
 | 3731 |     if (val == NULL) | 
 | 3732 | 	return(xmlXPathNewFloat(0.0)); | 
 | 3733 |     if (val->type == XPATH_NUMBER) | 
 | 3734 | 	return(val); | 
 | 3735 |     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); | 
 | 3736 |     xmlXPathFreeObject(val); | 
 | 3737 |     return(ret); | 
 | 3738 | } | 
 | 3739 |  | 
 | 3740 | /** | 
 | 3741 |  * xmlXPathCastNumberToBoolean: | 
 | 3742 |  * @val:  a number | 
 | 3743 |  * | 
 | 3744 |  * Converts a number to its boolean value | 
 | 3745 |  * | 
 | 3746 |  * Returns the boolean value | 
 | 3747 |  */ | 
 | 3748 | int | 
 | 3749 | xmlXPathCastNumberToBoolean (double val) { | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 3750 |      if (xmlXPathIsNaN(val) || (val == 0.0)) | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3751 | 	 return(0); | 
 | 3752 |      return(1); | 
 | 3753 | } | 
 | 3754 |  | 
 | 3755 | /** | 
 | 3756 |  * xmlXPathCastStringToBoolean: | 
 | 3757 |  * @val:  a string | 
 | 3758 |  * | 
 | 3759 |  * Converts a string to its boolean value | 
 | 3760 |  * | 
 | 3761 |  * Returns the boolean value | 
 | 3762 |  */ | 
 | 3763 | int | 
 | 3764 | xmlXPathCastStringToBoolean (const xmlChar *val) { | 
 | 3765 |     if ((val == NULL) || (xmlStrlen(val) == 0)) | 
 | 3766 | 	return(0); | 
 | 3767 |     return(1); | 
 | 3768 | } | 
 | 3769 |  | 
 | 3770 | /** | 
 | 3771 |  * xmlXPathCastNodeSetToBoolean: | 
 | 3772 |  * @ns:  a node-set | 
 | 3773 |  * | 
 | 3774 |  * Converts a node-set to its boolean value | 
 | 3775 |  * | 
 | 3776 |  * Returns the boolean value | 
 | 3777 |  */ | 
 | 3778 | int | 
 | 3779 | xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { | 
 | 3780 |     if ((ns == NULL) || (ns->nodeNr == 0)) | 
 | 3781 | 	return(0); | 
 | 3782 |     return(1); | 
 | 3783 | } | 
 | 3784 |  | 
 | 3785 | /** | 
| Daniel Veillard | 5e2dace | 2001-07-18 19:30:27 +0000 | [diff] [blame] | 3786 |  * xmlXPathCastToBoolean: | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3787 |  * @val:  an XPath object | 
 | 3788 |  * | 
 | 3789 |  * Converts an XPath object to its boolean value | 
 | 3790 |  * | 
 | 3791 |  * Returns the boolean value | 
 | 3792 |  */ | 
 | 3793 | int | 
 | 3794 | xmlXPathCastToBoolean (xmlXPathObjectPtr val) { | 
 | 3795 |     int ret = 0; | 
 | 3796 |  | 
 | 3797 |     if (val == NULL) | 
 | 3798 | 	return(0); | 
 | 3799 |     switch (val->type) { | 
 | 3800 |     case XPATH_UNDEFINED: | 
 | 3801 | #ifdef DEBUG_EXPR | 
 | 3802 | 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); | 
 | 3803 | #endif | 
 | 3804 | 	ret = 0; | 
 | 3805 | 	break; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3806 |     case XPATH_NODESET: | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 3807 |     case XPATH_XSLT_TREE: | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 3808 | 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); | 
 | 3809 | 	break; | 
 | 3810 |     case XPATH_STRING: | 
 | 3811 | 	ret = xmlXPathCastStringToBoolean(val->stringval); | 
 | 3812 | 	break; | 
 | 3813 |     case XPATH_NUMBER: | 
 | 3814 | 	ret = xmlXPathCastNumberToBoolean(val->floatval); | 
 | 3815 | 	break; | 
 | 3816 |     case XPATH_BOOLEAN: | 
 | 3817 | 	ret = val->boolval; | 
 | 3818 | 	break; | 
 | 3819 |     case XPATH_USERS: | 
 | 3820 |     case XPATH_POINT: | 
 | 3821 |     case XPATH_RANGE: | 
 | 3822 |     case XPATH_LOCATIONSET: | 
 | 3823 | 	TODO; | 
 | 3824 | 	ret = 0; | 
 | 3825 | 	break; | 
 | 3826 |     } | 
 | 3827 |     return(ret); | 
 | 3828 | } | 
 | 3829 |  | 
 | 3830 |  | 
 | 3831 | /** | 
 | 3832 |  * xmlXPathConvertBoolean: | 
 | 3833 |  * @val:  an XPath object | 
 | 3834 |  * | 
 | 3835 |  * Converts an existing object to its boolean() equivalent | 
 | 3836 |  * | 
 | 3837 |  * Returns the new object, the old one is freed (or the operation | 
 | 3838 |  *         is done directly on @val) | 
 | 3839 |  */ | 
 | 3840 | xmlXPathObjectPtr | 
 | 3841 | xmlXPathConvertBoolean(xmlXPathObjectPtr val) { | 
 | 3842 |     xmlXPathObjectPtr ret; | 
 | 3843 |  | 
 | 3844 |     if (val == NULL) | 
 | 3845 | 	return(xmlXPathNewBoolean(0)); | 
 | 3846 |     if (val->type == XPATH_BOOLEAN) | 
 | 3847 | 	return(val); | 
 | 3848 |     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); | 
 | 3849 |     xmlXPathFreeObject(val); | 
 | 3850 |     return(ret); | 
 | 3851 | } | 
 | 3852 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3853 | /************************************************************************ | 
 | 3854 |  *									* | 
 | 3855 |  *		Routines to handle XPath contexts			* | 
 | 3856 |  *									* | 
 | 3857 |  ************************************************************************/ | 
 | 3858 |  | 
 | 3859 | /** | 
 | 3860 |  * xmlXPathNewContext: | 
 | 3861 |  * @doc:  the XML document | 
 | 3862 |  * | 
 | 3863 |  * Create a new xmlXPathContext | 
 | 3864 |  * | 
| Daniel Veillard | af43f63 | 2002-03-08 15:05:20 +0000 | [diff] [blame] | 3865 |  * Returns the xmlXPathContext just allocated. The caller will need to free it. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3866 |  */ | 
 | 3867 | xmlXPathContextPtr | 
 | 3868 | xmlXPathNewContext(xmlDocPtr doc) { | 
 | 3869 |     xmlXPathContextPtr ret; | 
 | 3870 |  | 
 | 3871 |     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); | 
 | 3872 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3873 |         xmlXPathErrMemory(NULL, "creating context\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3874 | 	return(NULL); | 
 | 3875 |     } | 
 | 3876 |     memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); | 
 | 3877 |     ret->doc = doc; | 
 | 3878 |     ret->node = NULL; | 
 | 3879 |  | 
 | 3880 |     ret->varHash = NULL; | 
 | 3881 |  | 
 | 3882 |     ret->nb_types = 0; | 
 | 3883 |     ret->max_types = 0; | 
 | 3884 |     ret->types = NULL; | 
 | 3885 |  | 
 | 3886 |     ret->funcHash = xmlHashCreate(0); | 
 | 3887 |  | 
 | 3888 |     ret->nb_axis = 0; | 
 | 3889 |     ret->max_axis = 0; | 
 | 3890 |     ret->axis = NULL; | 
 | 3891 |  | 
 | 3892 |     ret->nsHash = NULL; | 
 | 3893 |     ret->user = NULL; | 
 | 3894 |  | 
 | 3895 |     ret->contextSize = -1; | 
 | 3896 |     ret->proximityPosition = -1; | 
 | 3897 |  | 
 | 3898 |     xmlXPathRegisterAllFunctions(ret); | 
 | 3899 |      | 
 | 3900 |     return(ret); | 
 | 3901 | } | 
 | 3902 |  | 
 | 3903 | /** | 
 | 3904 |  * xmlXPathFreeContext: | 
 | 3905 |  * @ctxt:  the context to free | 
 | 3906 |  * | 
 | 3907 |  * Free up an xmlXPathContext | 
 | 3908 |  */ | 
 | 3909 | void | 
 | 3910 | xmlXPathFreeContext(xmlXPathContextPtr ctxt) { | 
 | 3911 |     xmlXPathRegisteredNsCleanup(ctxt); | 
 | 3912 |     xmlXPathRegisteredFuncsCleanup(ctxt); | 
 | 3913 |     xmlXPathRegisteredVariablesCleanup(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3914 |     xmlFree(ctxt); | 
 | 3915 | } | 
 | 3916 |  | 
 | 3917 | /************************************************************************ | 
 | 3918 |  *									* | 
 | 3919 |  *		Routines to handle XPath parser contexts		* | 
 | 3920 |  *									* | 
 | 3921 |  ************************************************************************/ | 
 | 3922 |  | 
 | 3923 | #define CHECK_CTXT(ctxt)						\ | 
 | 3924 |     if (ctxt == NULL) { 						\ | 
 | 3925 |         xmlGenericError(xmlGenericErrorContext,				\ | 
 | 3926 | 		"%s:%d Internal error: ctxt == NULL\n",			\ | 
 | 3927 | 	        __FILE__, __LINE__);					\ | 
 | 3928 |     }									\ | 
 | 3929 |  | 
 | 3930 |  | 
 | 3931 | #define CHECK_CONTEXT(ctxt)						\ | 
| Daniel Veillard | 57b2516 | 2004-11-06 14:50:18 +0000 | [diff] [blame] | 3932 |     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\ | 
 | 3933 |         (ctxt->doc->children == NULL)) { 				\ | 
 | 3934 | 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\ | 
| Daniel Veillard | ce682bc | 2004-11-05 17:22:25 +0000 | [diff] [blame] | 3935 | 	return(NULL);							\ | 
| Daniel Veillard | 57b2516 | 2004-11-06 14:50:18 +0000 | [diff] [blame] | 3936 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3937 |  | 
 | 3938 |  | 
 | 3939 | /** | 
 | 3940 |  * xmlXPathNewParserContext: | 
 | 3941 |  * @str:  the XPath expression | 
 | 3942 |  * @ctxt:  the XPath context | 
 | 3943 |  * | 
 | 3944 |  * Create a new xmlXPathParserContext | 
 | 3945 |  * | 
 | 3946 |  * Returns the xmlXPathParserContext just allocated. | 
 | 3947 |  */ | 
 | 3948 | xmlXPathParserContextPtr | 
 | 3949 | xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { | 
 | 3950 |     xmlXPathParserContextPtr ret; | 
 | 3951 |  | 
 | 3952 |     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); | 
 | 3953 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3954 |         xmlXPathErrMemory(ctxt, "creating parser context\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3955 | 	return(NULL); | 
 | 3956 |     } | 
 | 3957 |     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); | 
 | 3958 |     ret->cur = ret->base = str; | 
 | 3959 |     ret->context = ctxt; | 
 | 3960 |  | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 3961 |     ret->comp = xmlXPathNewCompExpr(); | 
 | 3962 |     if (ret->comp == NULL) { | 
 | 3963 | 	xmlFree(ret->valueTab); | 
 | 3964 | 	xmlFree(ret); | 
 | 3965 | 	return(NULL); | 
 | 3966 |     } | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 3967 |     if ((ctxt != NULL) && (ctxt->dict != NULL)) { | 
 | 3968 |         ret->comp->dict = ctxt->dict; | 
 | 3969 | 	xmlDictReference(ret->comp->dict); | 
 | 3970 |     } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 3971 |  | 
 | 3972 |     return(ret); | 
 | 3973 | } | 
 | 3974 |  | 
 | 3975 | /** | 
 | 3976 |  * xmlXPathCompParserContext: | 
 | 3977 |  * @comp:  the XPath compiled expression | 
 | 3978 |  * @ctxt:  the XPath context | 
 | 3979 |  * | 
 | 3980 |  * Create a new xmlXPathParserContext when processing a compiled expression | 
 | 3981 |  * | 
 | 3982 |  * Returns the xmlXPathParserContext just allocated. | 
 | 3983 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 3984 | static xmlXPathParserContextPtr | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 3985 | xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { | 
 | 3986 |     xmlXPathParserContextPtr ret; | 
 | 3987 |  | 
 | 3988 |     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); | 
 | 3989 |     if (ret == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 3990 |         xmlXPathErrMemory(ctxt, "creating evaluation context\n"); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 3991 | 	return(NULL); | 
 | 3992 |     } | 
 | 3993 |     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); | 
 | 3994 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 3995 |     /* Allocate the value stack */ | 
 | 3996 |     ret->valueTab = (xmlXPathObjectPtr *)  | 
 | 3997 |                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 3998 |     if (ret->valueTab == NULL) { | 
 | 3999 | 	xmlFree(ret); | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 4000 | 	xmlXPathErrMemory(ctxt, "creating evaluation context\n"); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 4001 | 	return(NULL); | 
 | 4002 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4003 |     ret->valueNr = 0; | 
 | 4004 |     ret->valueMax = 10; | 
 | 4005 |     ret->value = NULL; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 4006 |  | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 4007 |     ret->context = ctxt; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 4008 |     ret->comp = comp; | 
 | 4009 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4010 |     return(ret); | 
 | 4011 | } | 
 | 4012 |  | 
 | 4013 | /** | 
 | 4014 |  * xmlXPathFreeParserContext: | 
 | 4015 |  * @ctxt:  the context to free | 
 | 4016 |  * | 
 | 4017 |  * Free up an xmlXPathParserContext | 
 | 4018 |  */ | 
 | 4019 | void | 
 | 4020 | xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { | 
 | 4021 |     if (ctxt->valueTab != NULL) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4022 |         xmlFree(ctxt->valueTab); | 
 | 4023 |     } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 4024 |     if (ctxt->comp) | 
 | 4025 | 	xmlXPathFreeCompExpr(ctxt->comp); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4026 |     xmlFree(ctxt); | 
 | 4027 | } | 
 | 4028 |  | 
 | 4029 | /************************************************************************ | 
 | 4030 |  *									* | 
 | 4031 |  *		The implicit core function library			* | 
 | 4032 |  *									* | 
 | 4033 |  ************************************************************************/ | 
 | 4034 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4035 | /** | 
| Daniel Veillard | 01c13b5 | 2002-12-10 15:19:08 +0000 | [diff] [blame] | 4036 |  * xmlXPathNodeValHash: | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4037 |  * @node:  a node pointer | 
 | 4038 |  * | 
 | 4039 |  * Function computing the beginning of the string value of the node, | 
 | 4040 |  * used to speed up comparisons | 
 | 4041 |  * | 
 | 4042 |  * Returns an int usable as a hash | 
 | 4043 |  */ | 
 | 4044 | static unsigned int | 
 | 4045 | xmlXPathNodeValHash(xmlNodePtr node) { | 
 | 4046 |     int len = 2; | 
 | 4047 |     const xmlChar * string = NULL; | 
 | 4048 |     xmlNodePtr tmp = NULL; | 
 | 4049 |     unsigned int ret = 0; | 
 | 4050 |  | 
 | 4051 |     if (node == NULL) | 
 | 4052 | 	return(0); | 
 | 4053 |  | 
| Daniel Veillard | 9adc046 | 2003-03-24 18:39:54 +0000 | [diff] [blame] | 4054 |     if (node->type == XML_DOCUMENT_NODE) { | 
 | 4055 | 	tmp = xmlDocGetRootElement((xmlDocPtr) node); | 
 | 4056 | 	if (tmp == NULL) | 
 | 4057 | 	    node = node->children; | 
 | 4058 | 	else | 
 | 4059 | 	    node = tmp; | 
 | 4060 |  | 
 | 4061 | 	if (node == NULL) | 
 | 4062 | 	    return(0); | 
 | 4063 |     } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4064 |  | 
 | 4065 |     switch (node->type) { | 
 | 4066 | 	case XML_COMMENT_NODE: | 
 | 4067 | 	case XML_PI_NODE: | 
 | 4068 | 	case XML_CDATA_SECTION_NODE: | 
 | 4069 | 	case XML_TEXT_NODE: | 
 | 4070 | 	    string = node->content; | 
 | 4071 | 	    if (string == NULL) | 
 | 4072 | 		return(0); | 
 | 4073 | 	    if (string[0] == 0) | 
 | 4074 | 		return(0); | 
 | 4075 | 	    return(((unsigned int) string[0]) + | 
 | 4076 | 		   (((unsigned int) string[1]) << 8)); | 
 | 4077 | 	case XML_NAMESPACE_DECL: | 
 | 4078 | 	    string = ((xmlNsPtr)node)->href; | 
 | 4079 | 	    if (string == NULL) | 
 | 4080 | 		return(0); | 
 | 4081 | 	    if (string[0] == 0) | 
 | 4082 | 		return(0); | 
 | 4083 | 	    return(((unsigned int) string[0]) + | 
 | 4084 | 		   (((unsigned int) string[1]) << 8)); | 
 | 4085 | 	case XML_ATTRIBUTE_NODE: | 
 | 4086 | 	    tmp = ((xmlAttrPtr) node)->children; | 
 | 4087 | 	    break; | 
 | 4088 | 	case XML_ELEMENT_NODE: | 
 | 4089 | 	    tmp = node->children; | 
 | 4090 | 	    break; | 
 | 4091 | 	default: | 
 | 4092 | 	    return(0); | 
 | 4093 |     } | 
 | 4094 |     while (tmp != NULL) { | 
 | 4095 | 	switch (tmp->type) { | 
 | 4096 | 	    case XML_COMMENT_NODE: | 
 | 4097 | 	    case XML_PI_NODE: | 
 | 4098 | 	    case XML_CDATA_SECTION_NODE: | 
 | 4099 | 	    case XML_TEXT_NODE: | 
 | 4100 | 		string = tmp->content; | 
 | 4101 | 		break; | 
 | 4102 | 	    case XML_NAMESPACE_DECL: | 
 | 4103 | 		string = ((xmlNsPtr)tmp)->href; | 
 | 4104 | 		break; | 
 | 4105 | 	    default: | 
 | 4106 | 		break; | 
 | 4107 | 	} | 
 | 4108 | 	if ((string != NULL) && (string[0] != 0)) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4109 | 	    if (len == 1) { | 
 | 4110 | 		return(ret + (((unsigned int) string[0]) << 8)); | 
 | 4111 | 	    } | 
 | 4112 | 	    if (string[1] == 0) { | 
 | 4113 | 		len = 1; | 
 | 4114 | 		ret = (unsigned int) string[0]; | 
 | 4115 | 	    } else { | 
 | 4116 | 		return(((unsigned int) string[0]) + | 
 | 4117 | 		       (((unsigned int) string[1]) << 8)); | 
 | 4118 | 	    } | 
 | 4119 | 	} | 
 | 4120 | 	/* | 
 | 4121 | 	 * Skip to next node | 
 | 4122 | 	 */ | 
 | 4123 | 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { | 
 | 4124 | 	    if (tmp->children->type != XML_ENTITY_DECL) { | 
 | 4125 | 		tmp = tmp->children; | 
 | 4126 | 		continue; | 
 | 4127 | 	    } | 
 | 4128 | 	} | 
 | 4129 | 	if (tmp == node) | 
 | 4130 | 	    break; | 
 | 4131 |  | 
 | 4132 | 	if (tmp->next != NULL) { | 
 | 4133 | 	    tmp = tmp->next; | 
 | 4134 | 	    continue; | 
 | 4135 | 	} | 
 | 4136 | 	 | 
 | 4137 | 	do { | 
 | 4138 | 	    tmp = tmp->parent; | 
 | 4139 | 	    if (tmp == NULL) | 
 | 4140 | 		break; | 
 | 4141 | 	    if (tmp == node) { | 
 | 4142 | 		tmp = NULL; | 
 | 4143 | 		break; | 
 | 4144 | 	    } | 
 | 4145 | 	    if (tmp->next != NULL) { | 
 | 4146 | 		tmp = tmp->next; | 
 | 4147 | 		break; | 
 | 4148 | 	    } | 
 | 4149 | 	} while (tmp != NULL); | 
 | 4150 |     } | 
 | 4151 |     return(ret); | 
 | 4152 | } | 
 | 4153 |  | 
 | 4154 | /** | 
 | 4155 |  * xmlXPathStringHash: | 
 | 4156 |  * @string:  a string | 
 | 4157 |  * | 
 | 4158 |  * Function computing the beginning of the string value of the node, | 
 | 4159 |  * used to speed up comparisons | 
 | 4160 |  * | 
 | 4161 |  * Returns an int usable as a hash | 
 | 4162 |  */ | 
 | 4163 | static unsigned int | 
 | 4164 | xmlXPathStringHash(const xmlChar * string) { | 
 | 4165 |     if (string == NULL) | 
 | 4166 | 	return((unsigned int) 0); | 
 | 4167 |     if (string[0] == 0) | 
 | 4168 | 	return(0); | 
 | 4169 |     return(((unsigned int) string[0]) + | 
 | 4170 | 	   (((unsigned int) string[1]) << 8)); | 
 | 4171 | } | 
 | 4172 |  | 
 | 4173 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4174 |  * xmlXPathCompareNodeSetFloat: | 
 | 4175 |  * @ctxt:  the XPath Parser context | 
 | 4176 |  * @inf:  less than (1) or greater than (0) | 
 | 4177 |  * @strict:  is the comparison strict | 
 | 4178 |  * @arg:  the node set | 
 | 4179 |  * @f:  the value | 
 | 4180 |  * | 
 | 4181 |  * Implement the compare operation between a nodeset and a number | 
 | 4182 |  *     @ns < @val    (1, 1, ... | 
 | 4183 |  *     @ns <= @val   (1, 0, ... | 
 | 4184 |  *     @ns > @val    (0, 1, ... | 
 | 4185 |  *     @ns >= @val   (0, 0, ... | 
 | 4186 |  * | 
 | 4187 |  * If one object to be compared is a node-set and the other is a number, | 
 | 4188 |  * then the comparison will be true if and only if there is a node in the | 
 | 4189 |  * node-set such that the result of performing the comparison on the number | 
 | 4190 |  * to be compared and on the result of converting the string-value of that | 
 | 4191 |  * node to a number using the number function is true. | 
 | 4192 |  * | 
 | 4193 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4194 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4195 | static int | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4196 | xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, | 
 | 4197 | 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { | 
 | 4198 |     int i, ret = 0; | 
 | 4199 |     xmlNodeSetPtr ns; | 
 | 4200 |     xmlChar *str2; | 
 | 4201 |  | 
 | 4202 |     if ((f == NULL) || (arg == NULL) || | 
 | 4203 | 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { | 
 | 4204 | 	xmlXPathFreeObject(arg); | 
 | 4205 | 	xmlXPathFreeObject(f); | 
 | 4206 |         return(0); | 
 | 4207 |     } | 
 | 4208 |     ns = arg->nodesetval; | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 4209 |     if (ns != NULL) { | 
 | 4210 | 	for (i = 0;i < ns->nodeNr;i++) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 4211 | 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 4212 | 	     if (str2 != NULL) { | 
 | 4213 | 		 valuePush(ctxt, | 
 | 4214 | 			   xmlXPathNewString(str2)); | 
 | 4215 | 		 xmlFree(str2); | 
 | 4216 | 		 xmlXPathNumberFunction(ctxt, 1); | 
 | 4217 | 		 valuePush(ctxt, xmlXPathObjectCopy(f)); | 
 | 4218 | 		 ret = xmlXPathCompareValues(ctxt, inf, strict); | 
 | 4219 | 		 if (ret) | 
 | 4220 | 		     break; | 
 | 4221 | 	     } | 
 | 4222 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4223 |     } | 
 | 4224 |     xmlXPathFreeObject(arg); | 
 | 4225 |     xmlXPathFreeObject(f); | 
 | 4226 |     return(ret); | 
 | 4227 | } | 
 | 4228 |  | 
 | 4229 | /** | 
 | 4230 |  * xmlXPathCompareNodeSetString: | 
 | 4231 |  * @ctxt:  the XPath Parser context | 
 | 4232 |  * @inf:  less than (1) or greater than (0) | 
 | 4233 |  * @strict:  is the comparison strict | 
 | 4234 |  * @arg:  the node set | 
 | 4235 |  * @s:  the value | 
 | 4236 |  * | 
 | 4237 |  * Implement the compare operation between a nodeset and a string | 
 | 4238 |  *     @ns < @val    (1, 1, ... | 
 | 4239 |  *     @ns <= @val   (1, 0, ... | 
 | 4240 |  *     @ns > @val    (0, 1, ... | 
 | 4241 |  *     @ns >= @val   (0, 0, ... | 
 | 4242 |  * | 
 | 4243 |  * If one object to be compared is a node-set and the other is a string, | 
 | 4244 |  * then the comparison will be true if and only if there is a node in | 
 | 4245 |  * the node-set such that the result of performing the comparison on the | 
 | 4246 |  * string-value of the node and the other string is true. | 
 | 4247 |  * | 
 | 4248 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4249 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4250 | static int | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4251 | xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, | 
 | 4252 | 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { | 
 | 4253 |     int i, ret = 0; | 
 | 4254 |     xmlNodeSetPtr ns; | 
 | 4255 |     xmlChar *str2; | 
 | 4256 |  | 
 | 4257 |     if ((s == NULL) || (arg == NULL) || | 
 | 4258 | 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { | 
 | 4259 | 	xmlXPathFreeObject(arg); | 
 | 4260 | 	xmlXPathFreeObject(s); | 
 | 4261 |         return(0); | 
 | 4262 |     } | 
 | 4263 |     ns = arg->nodesetval; | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 4264 |     if (ns != NULL) { | 
 | 4265 | 	for (i = 0;i < ns->nodeNr;i++) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 4266 | 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 4267 | 	     if (str2 != NULL) { | 
 | 4268 | 		 valuePush(ctxt, | 
 | 4269 | 			   xmlXPathNewString(str2)); | 
 | 4270 | 		 xmlFree(str2); | 
 | 4271 | 		 valuePush(ctxt, xmlXPathObjectCopy(s)); | 
 | 4272 | 		 ret = xmlXPathCompareValues(ctxt, inf, strict); | 
 | 4273 | 		 if (ret) | 
 | 4274 | 		     break; | 
 | 4275 | 	     } | 
 | 4276 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4277 |     } | 
 | 4278 |     xmlXPathFreeObject(arg); | 
 | 4279 |     xmlXPathFreeObject(s); | 
 | 4280 |     return(ret); | 
 | 4281 | } | 
 | 4282 |  | 
 | 4283 | /** | 
 | 4284 |  * xmlXPathCompareNodeSets: | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 4285 |  * @inf:  less than (1) or greater than (0) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4286 |  * @strict:  is the comparison strict | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 4287 |  * @arg1:  the first node set object | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4288 |  * @arg2:  the second node set object | 
 | 4289 |  * | 
 | 4290 |  * Implement the compare operation on nodesets: | 
 | 4291 |  * | 
 | 4292 |  * If both objects to be compared are node-sets, then the comparison | 
 | 4293 |  * will be true if and only if there is a node in the first node-set | 
 | 4294 |  * and a node in the second node-set such that the result of performing | 
 | 4295 |  * the comparison on the string-values of the two nodes is true.  | 
 | 4296 |  * .... | 
 | 4297 |  * When neither object to be compared is a node-set and the operator | 
 | 4298 |  * is <=, <, >= or >, then the objects are compared by converting both | 
 | 4299 |  * objects to numbers and comparing the numbers according to IEEE 754. | 
 | 4300 |  * .... | 
 | 4301 |  * The number function converts its argument to a number as follows: | 
 | 4302 |  *  - a string that consists of optional whitespace followed by an | 
 | 4303 |  *    optional minus sign followed by a Number followed by whitespace | 
 | 4304 |  *    is converted to the IEEE 754 number that is nearest (according | 
 | 4305 |  *    to the IEEE 754 round-to-nearest rule) to the mathematical value | 
 | 4306 |  *    represented by the string; any other string is converted to NaN | 
 | 4307 |  * | 
 | 4308 |  * Conclusion all nodes need to be converted first to their string value | 
 | 4309 |  * and then the comparison must be done when possible  | 
 | 4310 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4311 | static int | 
 | 4312 | xmlXPathCompareNodeSets(int inf, int strict, | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4313 | 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { | 
 | 4314 |     int i, j, init = 0; | 
 | 4315 |     double val1; | 
 | 4316 |     double *values2; | 
 | 4317 |     int ret = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4318 |     xmlNodeSetPtr ns1; | 
 | 4319 |     xmlNodeSetPtr ns2; | 
 | 4320 |  | 
 | 4321 |     if ((arg1 == NULL) || | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4322 | 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { | 
 | 4323 | 	xmlXPathFreeObject(arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4324 |         return(0); | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4325 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4326 |     if ((arg2 == NULL) || | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4327 | 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { | 
 | 4328 | 	xmlXPathFreeObject(arg1); | 
 | 4329 | 	xmlXPathFreeObject(arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4330 |         return(0); | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4331 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4332 |  | 
 | 4333 |     ns1 = arg1->nodesetval; | 
 | 4334 |     ns2 = arg2->nodesetval; | 
 | 4335 |  | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 4336 |     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4337 | 	xmlXPathFreeObject(arg1); | 
 | 4338 | 	xmlXPathFreeObject(arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4339 | 	return(0); | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4340 |     } | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 4341 |     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4342 | 	xmlXPathFreeObject(arg1); | 
 | 4343 | 	xmlXPathFreeObject(arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4344 | 	return(0); | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4345 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4346 |  | 
 | 4347 |     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); | 
 | 4348 |     if (values2 == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 4349 |         xmlXPathErrMemory(NULL, "comparing nodesets\n"); | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4350 | 	xmlXPathFreeObject(arg1); | 
 | 4351 | 	xmlXPathFreeObject(arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4352 | 	return(0); | 
 | 4353 |     } | 
 | 4354 |     for (i = 0;i < ns1->nodeNr;i++) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 4355 | 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 4356 | 	if (xmlXPathIsNaN(val1)) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4357 | 	    continue; | 
 | 4358 | 	for (j = 0;j < ns2->nodeNr;j++) { | 
 | 4359 | 	    if (init == 0) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 4360 | 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4361 | 	    } | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 4362 | 	    if (xmlXPathIsNaN(values2[j])) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4363 | 		continue; | 
 | 4364 | 	    if (inf && strict)  | 
 | 4365 | 		ret = (val1 < values2[j]); | 
 | 4366 | 	    else if (inf && !strict) | 
 | 4367 | 		ret = (val1 <= values2[j]); | 
 | 4368 | 	    else if (!inf && strict) | 
 | 4369 | 		ret = (val1 > values2[j]); | 
 | 4370 | 	    else if (!inf && !strict) | 
 | 4371 | 		ret = (val1 >= values2[j]); | 
 | 4372 | 	    if (ret) | 
 | 4373 | 		break; | 
 | 4374 | 	} | 
 | 4375 | 	if (ret) | 
 | 4376 | 	    break; | 
 | 4377 | 	init = 1; | 
 | 4378 |     } | 
 | 4379 |     xmlFree(values2); | 
| Daniel Veillard | 4dd9346 | 2001-04-02 15:16:19 +0000 | [diff] [blame] | 4380 |     xmlXPathFreeObject(arg1); | 
 | 4381 |     xmlXPathFreeObject(arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4382 |     return(ret); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4383 | } | 
 | 4384 |  | 
 | 4385 | /** | 
 | 4386 |  * xmlXPathCompareNodeSetValue: | 
 | 4387 |  * @ctxt:  the XPath Parser context | 
 | 4388 |  * @inf:  less than (1) or greater than (0) | 
 | 4389 |  * @strict:  is the comparison strict | 
 | 4390 |  * @arg:  the node set | 
 | 4391 |  * @val:  the value | 
 | 4392 |  * | 
 | 4393 |  * Implement the compare operation between a nodeset and a value | 
 | 4394 |  *     @ns < @val    (1, 1, ... | 
 | 4395 |  *     @ns <= @val   (1, 0, ... | 
 | 4396 |  *     @ns > @val    (0, 1, ... | 
 | 4397 |  *     @ns >= @val   (0, 0, ... | 
 | 4398 |  * | 
 | 4399 |  * If one object to be compared is a node-set and the other is a boolean, | 
 | 4400 |  * then the comparison will be true if and only if the result of performing | 
 | 4401 |  * the comparison on the boolean and on the result of converting | 
 | 4402 |  * the node-set to a boolean using the boolean function is true. | 
 | 4403 |  * | 
 | 4404 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4405 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4406 | static int | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4407 | xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, | 
 | 4408 | 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { | 
 | 4409 |     if ((val == NULL) || (arg == NULL) || | 
 | 4410 | 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) | 
 | 4411 |         return(0); | 
 | 4412 |  | 
 | 4413 |     switch(val->type) { | 
 | 4414 |         case XPATH_NUMBER: | 
 | 4415 | 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); | 
 | 4416 |         case XPATH_NODESET: | 
 | 4417 |         case XPATH_XSLT_TREE: | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4418 | 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4419 |         case XPATH_STRING: | 
 | 4420 | 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); | 
 | 4421 |         case XPATH_BOOLEAN: | 
 | 4422 | 	    valuePush(ctxt, arg); | 
 | 4423 | 	    xmlXPathBooleanFunction(ctxt, 1); | 
 | 4424 | 	    valuePush(ctxt, val); | 
 | 4425 | 	    return(xmlXPathCompareValues(ctxt, inf, strict)); | 
 | 4426 | 	default: | 
 | 4427 | 	    TODO | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4428 |     } | 
 | 4429 |     return(0); | 
 | 4430 | } | 
 | 4431 |  | 
 | 4432 | /** | 
| Daniel Veillard | 01c13b5 | 2002-12-10 15:19:08 +0000 | [diff] [blame] | 4433 |  * xmlXPathEqualNodeSetString: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4434 |  * @arg:  the nodeset object argument | 
 | 4435 |  * @str:  the string to compare to. | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4436 |  * @neq:  flag to show whether for '=' (0) or '!=' (1) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4437 |  * | 
 | 4438 |  * Implement the equal operation on XPath objects content: @arg1 == @arg2 | 
 | 4439 |  * If one object to be compared is a node-set and the other is a string, | 
 | 4440 |  * then the comparison will be true if and only if there is a node in | 
 | 4441 |  * the node-set such that the result of performing the comparison on the | 
 | 4442 |  * string-value of the node and the other string is true. | 
 | 4443 |  * | 
 | 4444 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4445 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4446 | static int | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4447 | xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4448 | { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4449 |     int i; | 
 | 4450 |     xmlNodeSetPtr ns; | 
 | 4451 |     xmlChar *str2; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4452 |     unsigned int hash; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4453 |  | 
 | 4454 |     if ((str == NULL) || (arg == NULL) || | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4455 |         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) | 
 | 4456 |         return (0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4457 |     ns = arg->nodesetval; | 
| William M. Brack | c125a72 | 2003-11-16 08:06:19 +0000 | [diff] [blame] | 4458 |     /* | 
 | 4459 |      * A NULL nodeset compared with a string is always false | 
 | 4460 |      * (since there is no node equal, and no node not equal) | 
 | 4461 |      */ | 
 | 4462 |     if ((ns == NULL) || (ns->nodeNr <= 0) ) | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4463 |         return (0); | 
| William M. Brack | c125a72 | 2003-11-16 08:06:19 +0000 | [diff] [blame] | 4464 |     hash = xmlXPathStringHash(str); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4465 |     for (i = 0; i < ns->nodeNr; i++) { | 
 | 4466 |         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { | 
 | 4467 |             str2 = xmlNodeGetContent(ns->nodeTab[i]); | 
 | 4468 |             if ((str2 != NULL) && (xmlStrEqual(str, str2))) { | 
 | 4469 |                 xmlFree(str2); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4470 | 		if (neq) | 
 | 4471 | 		    continue; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4472 |                 return (1); | 
| Daniel Veillard | 9adc046 | 2003-03-24 18:39:54 +0000 | [diff] [blame] | 4473 | 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { | 
 | 4474 | 		if (neq) | 
 | 4475 | 		    continue; | 
 | 4476 |                 return (1); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4477 |             } else if (neq) { | 
 | 4478 | 		if (str2 != NULL) | 
 | 4479 | 		    xmlFree(str2); | 
 | 4480 | 		return (1); | 
 | 4481 | 	    } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4482 |             if (str2 != NULL) | 
 | 4483 |                 xmlFree(str2); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4484 |         } else if (neq) | 
 | 4485 | 	    return (1); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4486 |     } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4487 |     return (0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4488 | } | 
 | 4489 |  | 
 | 4490 | /** | 
| Daniel Veillard | 01c13b5 | 2002-12-10 15:19:08 +0000 | [diff] [blame] | 4491 |  * xmlXPathEqualNodeSetFloat: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4492 |  * @arg:  the nodeset object argument | 
 | 4493 |  * @f:  the float to compare to | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4494 |  * @neq:  flag to show whether to compare '=' (0) or '!=' (1) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4495 |  * | 
 | 4496 |  * Implement the equal operation on XPath objects content: @arg1 == @arg2 | 
 | 4497 |  * If one object to be compared is a node-set and the other is a number, | 
 | 4498 |  * then the comparison will be true if and only if there is a node in | 
 | 4499 |  * the node-set such that the result of performing the comparison on the | 
 | 4500 |  * number to be compared and on the result of converting the string-value | 
 | 4501 |  * of that node to a number using the number function is true. | 
 | 4502 |  * | 
 | 4503 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4504 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4505 | static int | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4506 | xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, | 
 | 4507 |     xmlXPathObjectPtr arg, double f, int neq) { | 
 | 4508 |   int i, ret=0; | 
 | 4509 |   xmlNodeSetPtr ns; | 
 | 4510 |   xmlChar *str2; | 
 | 4511 |   xmlXPathObjectPtr val; | 
 | 4512 |   double v; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4513 |  | 
 | 4514 |     if ((arg == NULL) || | 
 | 4515 | 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) | 
 | 4516 |         return(0); | 
 | 4517 |  | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4518 |     ns = arg->nodesetval; | 
 | 4519 |     if (ns != NULL) { | 
 | 4520 | 	for (i=0;i<ns->nodeNr;i++) { | 
 | 4521 | 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); | 
 | 4522 | 	    if (str2 != NULL) { | 
 | 4523 | 		valuePush(ctxt, xmlXPathNewString(str2)); | 
 | 4524 | 		xmlFree(str2); | 
 | 4525 | 		xmlXPathNumberFunction(ctxt, 1); | 
 | 4526 | 		val = valuePop(ctxt); | 
 | 4527 | 		v = val->floatval; | 
 | 4528 | 		xmlXPathFreeObject(val); | 
 | 4529 | 		if (!xmlXPathIsNaN(v)) { | 
 | 4530 | 		    if ((!neq) && (v==f)) { | 
 | 4531 | 			ret = 1; | 
 | 4532 | 			break; | 
 | 4533 | 		    } else if ((neq) && (v!=f)) { | 
 | 4534 | 			ret = 1; | 
 | 4535 | 			break; | 
 | 4536 | 		    } | 
 | 4537 | 		} | 
 | 4538 | 	    } | 
 | 4539 | 	} | 
 | 4540 |     } | 
 | 4541 |  | 
 | 4542 |     return(ret); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4543 | } | 
 | 4544 |  | 
 | 4545 |  | 
 | 4546 | /** | 
| Daniel Veillard | 01c13b5 | 2002-12-10 15:19:08 +0000 | [diff] [blame] | 4547 |  * xmlXPathEqualNodeSets: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4548 |  * @arg1:  first nodeset object argument | 
 | 4549 |  * @arg2:  second nodeset object argument | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4550 |  * @neq:   flag to show whether to test '=' (0) or '!=' (1) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4551 |  * | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4552 |  * Implement the equal / not equal operation on XPath nodesets: | 
 | 4553 |  * @arg1 == @arg2  or  @arg1 != @arg2 | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4554 |  * If both objects to be compared are node-sets, then the comparison | 
 | 4555 |  * will be true if and only if there is a node in the first node-set and | 
 | 4556 |  * a node in the second node-set such that the result of performing the | 
 | 4557 |  * comparison on the string-values of the two nodes is true. | 
 | 4558 |  * | 
 | 4559 |  * (needless to say, this is a costly operation) | 
 | 4560 |  * | 
 | 4561 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4562 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 4563 | static int | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4564 | xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4565 |     int i, j; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4566 |     unsigned int *hashs1; | 
 | 4567 |     unsigned int *hashs2; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4568 |     xmlChar **values1; | 
 | 4569 |     xmlChar **values2; | 
 | 4570 |     int ret = 0; | 
 | 4571 |     xmlNodeSetPtr ns1; | 
 | 4572 |     xmlNodeSetPtr ns2; | 
 | 4573 |  | 
 | 4574 |     if ((arg1 == NULL) || | 
 | 4575 | 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) | 
 | 4576 |         return(0); | 
 | 4577 |     if ((arg2 == NULL) || | 
 | 4578 | 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) | 
 | 4579 |         return(0); | 
 | 4580 |  | 
 | 4581 |     ns1 = arg1->nodesetval; | 
 | 4582 |     ns2 = arg2->nodesetval; | 
 | 4583 |  | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 4584 |     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4585 | 	return(0); | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 4586 |     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4587 | 	return(0); | 
 | 4588 |  | 
 | 4589 |     /* | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4590 |      * for equal, check if there is a node pertaining to both sets | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4591 |      */ | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4592 |     if (neq == 0) | 
 | 4593 | 	for (i = 0;i < ns1->nodeNr;i++) | 
 | 4594 | 	    for (j = 0;j < ns2->nodeNr;j++) | 
 | 4595 | 		if (ns1->nodeTab[i] == ns2->nodeTab[j]) | 
 | 4596 | 		    return(1); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4597 |  | 
 | 4598 |     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 4599 |     if (values1 == NULL) { | 
 | 4600 |         xmlXPathErrMemory(NULL, "comparing nodesets\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4601 | 	return(0); | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 4602 |     } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4603 |     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); | 
 | 4604 |     if (hashs1 == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 4605 |         xmlXPathErrMemory(NULL, "comparing nodesets\n"); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4606 | 	xmlFree(values1); | 
 | 4607 | 	return(0); | 
 | 4608 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4609 |     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); | 
 | 4610 |     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); | 
 | 4611 |     if (values2 == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 4612 |         xmlXPathErrMemory(NULL, "comparing nodesets\n"); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4613 | 	xmlFree(hashs1); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4614 | 	xmlFree(values1); | 
 | 4615 | 	return(0); | 
 | 4616 |     } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4617 |     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); | 
 | 4618 |     if (hashs2 == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 4619 |         xmlXPathErrMemory(NULL, "comparing nodesets\n"); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4620 | 	xmlFree(hashs1); | 
 | 4621 | 	xmlFree(values1); | 
 | 4622 | 	xmlFree(values2); | 
 | 4623 | 	return(0); | 
 | 4624 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4625 |     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); | 
 | 4626 |     for (i = 0;i < ns1->nodeNr;i++) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4627 | 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4628 | 	for (j = 0;j < ns2->nodeNr;j++) { | 
 | 4629 | 	    if (i == 0) | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4630 | 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4631 | 	    if (hashs1[i] != hashs2[j]) { | 
 | 4632 | 		if (neq) { | 
 | 4633 | 		    ret = 1; | 
 | 4634 | 		    break; | 
 | 4635 | 		} | 
 | 4636 | 	    } | 
 | 4637 | 	    else { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4638 | 		if (values1[i] == NULL) | 
 | 4639 | 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); | 
 | 4640 | 		if (values2[j] == NULL) | 
 | 4641 | 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4642 | 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4643 | 		if (ret) | 
 | 4644 | 		    break; | 
 | 4645 | 	    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4646 | 	} | 
 | 4647 | 	if (ret) | 
 | 4648 | 	    break; | 
 | 4649 |     } | 
 | 4650 |     for (i = 0;i < ns1->nodeNr;i++) | 
 | 4651 | 	if (values1[i] != NULL) | 
 | 4652 | 	    xmlFree(values1[i]); | 
 | 4653 |     for (j = 0;j < ns2->nodeNr;j++) | 
 | 4654 | 	if (values2[j] != NULL) | 
 | 4655 | 	    xmlFree(values2[j]); | 
 | 4656 |     xmlFree(values1); | 
 | 4657 |     xmlFree(values2); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 4658 |     xmlFree(hashs1); | 
 | 4659 |     xmlFree(hashs2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4660 |     return(ret); | 
 | 4661 | } | 
 | 4662 |  | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4663 | static int | 
 | 4664 | xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, | 
 | 4665 |   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4666 |     int ret = 0; | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4667 |     /* | 
 | 4668 |      *At this point we are assured neither arg1 nor arg2 | 
 | 4669 |      *is a nodeset, so we can just pick the appropriate routine. | 
 | 4670 |      */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4671 |     switch (arg1->type) { | 
 | 4672 |         case XPATH_UNDEFINED: | 
 | 4673 | #ifdef DEBUG_EXPR | 
 | 4674 | 	    xmlGenericError(xmlGenericErrorContext, | 
 | 4675 | 		    "Equal: undefined\n"); | 
 | 4676 | #endif | 
 | 4677 | 	    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4678 |         case XPATH_BOOLEAN: | 
 | 4679 | 	    switch (arg2->type) { | 
 | 4680 | 	        case XPATH_UNDEFINED: | 
 | 4681 | #ifdef DEBUG_EXPR | 
 | 4682 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 4683 | 			    "Equal: undefined\n"); | 
 | 4684 | #endif | 
 | 4685 | 		    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4686 | 		case XPATH_BOOLEAN: | 
 | 4687 | #ifdef DEBUG_EXPR | 
 | 4688 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 4689 | 			    "Equal: %d boolean %d \n", | 
 | 4690 | 			    arg1->boolval, arg2->boolval); | 
 | 4691 | #endif | 
 | 4692 | 		    ret = (arg1->boolval == arg2->boolval); | 
 | 4693 | 		    break; | 
 | 4694 | 		case XPATH_NUMBER: | 
| William M. Brack | ef61d20 | 2002-07-19 08:32:00 +0000 | [diff] [blame] | 4695 | 		    ret = (arg1->boolval == | 
 | 4696 | 			   xmlXPathCastNumberToBoolean(arg2->floatval)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4697 | 		    break; | 
 | 4698 | 		case XPATH_STRING: | 
 | 4699 | 		    if ((arg2->stringval == NULL) || | 
 | 4700 | 			(arg2->stringval[0] == 0)) ret = 0; | 
 | 4701 | 		    else  | 
 | 4702 | 			ret = 1; | 
 | 4703 | 		    ret = (arg1->boolval == ret); | 
 | 4704 | 		    break; | 
 | 4705 | 		case XPATH_USERS: | 
 | 4706 | 		case XPATH_POINT: | 
 | 4707 | 		case XPATH_RANGE: | 
 | 4708 | 		case XPATH_LOCATIONSET: | 
 | 4709 | 		    TODO | 
 | 4710 | 		    break; | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4711 | 		case XPATH_NODESET: | 
 | 4712 | 		case XPATH_XSLT_TREE: | 
 | 4713 | 		    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4714 | 	    } | 
 | 4715 | 	    break; | 
 | 4716 |         case XPATH_NUMBER: | 
 | 4717 | 	    switch (arg2->type) { | 
 | 4718 | 	        case XPATH_UNDEFINED: | 
 | 4719 | #ifdef DEBUG_EXPR | 
 | 4720 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 4721 | 			    "Equal: undefined\n"); | 
 | 4722 | #endif | 
 | 4723 | 		    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4724 | 		case XPATH_BOOLEAN: | 
| William M. Brack | ef61d20 | 2002-07-19 08:32:00 +0000 | [diff] [blame] | 4725 | 		    ret = (arg2->boolval== | 
 | 4726 | 			   xmlXPathCastNumberToBoolean(arg1->floatval)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4727 | 		    break; | 
 | 4728 | 		case XPATH_STRING: | 
 | 4729 | 		    valuePush(ctxt, arg2); | 
 | 4730 | 		    xmlXPathNumberFunction(ctxt, 1); | 
 | 4731 | 		    arg2 = valuePop(ctxt); | 
 | 4732 | 		    /* no break on purpose */ | 
 | 4733 | 		case XPATH_NUMBER: | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 4734 | 		    /* Hand check NaN and Infinity equalities */ | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 4735 | 		    if (xmlXPathIsNaN(arg1->floatval) || | 
 | 4736 | 		    	    xmlXPathIsNaN(arg2->floatval)) { | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 4737 | 		        ret = 0; | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 4738 | 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) { | 
 | 4739 | 		        if (xmlXPathIsInf(arg2->floatval) == 1) | 
 | 4740 | 			    ret = 1; | 
 | 4741 | 			else | 
 | 4742 | 			    ret = 0; | 
 | 4743 | 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) { | 
 | 4744 | 			if (xmlXPathIsInf(arg2->floatval) == -1) | 
 | 4745 | 			    ret = 1; | 
 | 4746 | 			else | 
 | 4747 | 			    ret = 0; | 
 | 4748 | 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) { | 
 | 4749 | 			if (xmlXPathIsInf(arg1->floatval) == 1) | 
 | 4750 | 			    ret = 1; | 
 | 4751 | 			else | 
 | 4752 | 			    ret = 0; | 
 | 4753 | 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) { | 
 | 4754 | 			if (xmlXPathIsInf(arg1->floatval) == -1) | 
 | 4755 | 			    ret = 1; | 
 | 4756 | 			else | 
 | 4757 | 			    ret = 0; | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 4758 | 		    } else { | 
 | 4759 | 		        ret = (arg1->floatval == arg2->floatval); | 
 | 4760 | 		    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4761 | 		    break; | 
 | 4762 | 		case XPATH_USERS: | 
 | 4763 | 		case XPATH_POINT: | 
 | 4764 | 		case XPATH_RANGE: | 
 | 4765 | 		case XPATH_LOCATIONSET: | 
 | 4766 | 		    TODO | 
 | 4767 | 		    break; | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4768 | 		case XPATH_NODESET: | 
 | 4769 | 		case XPATH_XSLT_TREE: | 
 | 4770 | 		    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4771 | 	    } | 
 | 4772 | 	    break; | 
 | 4773 |         case XPATH_STRING: | 
 | 4774 | 	    switch (arg2->type) { | 
 | 4775 | 	        case XPATH_UNDEFINED: | 
 | 4776 | #ifdef DEBUG_EXPR | 
 | 4777 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 4778 | 			    "Equal: undefined\n"); | 
 | 4779 | #endif | 
 | 4780 | 		    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4781 | 		case XPATH_BOOLEAN: | 
 | 4782 | 		    if ((arg1->stringval == NULL) || | 
 | 4783 | 			(arg1->stringval[0] == 0)) ret = 0; | 
 | 4784 | 		    else  | 
 | 4785 | 			ret = 1; | 
 | 4786 | 		    ret = (arg2->boolval == ret); | 
 | 4787 | 		    break; | 
 | 4788 | 		case XPATH_STRING: | 
 | 4789 | 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval); | 
 | 4790 | 		    break; | 
 | 4791 | 		case XPATH_NUMBER: | 
 | 4792 | 		    valuePush(ctxt, arg1); | 
 | 4793 | 		    xmlXPathNumberFunction(ctxt, 1); | 
 | 4794 | 		    arg1 = valuePop(ctxt); | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 4795 | 		    /* Hand check NaN and Infinity equalities */ | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 4796 | 		    if (xmlXPathIsNaN(arg1->floatval) || | 
 | 4797 | 		    	    xmlXPathIsNaN(arg2->floatval)) { | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 4798 | 		        ret = 0; | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 4799 | 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) { | 
 | 4800 | 			if (xmlXPathIsInf(arg2->floatval) == 1) | 
 | 4801 | 			    ret = 1; | 
 | 4802 | 			else | 
 | 4803 | 			    ret = 0; | 
 | 4804 | 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) { | 
 | 4805 | 			if (xmlXPathIsInf(arg2->floatval) == -1) | 
 | 4806 | 			    ret = 1; | 
 | 4807 | 			else | 
 | 4808 | 			    ret = 0; | 
 | 4809 | 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) { | 
 | 4810 | 			if (xmlXPathIsInf(arg1->floatval) == 1) | 
 | 4811 | 			    ret = 1; | 
 | 4812 | 			else | 
 | 4813 | 			    ret = 0; | 
 | 4814 | 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) { | 
 | 4815 | 			if (xmlXPathIsInf(arg1->floatval) == -1) | 
 | 4816 | 			    ret = 1; | 
 | 4817 | 			else | 
 | 4818 | 			    ret = 0; | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 4819 | 		    } else { | 
 | 4820 | 		        ret = (arg1->floatval == arg2->floatval); | 
 | 4821 | 		    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4822 | 		    break; | 
 | 4823 | 		case XPATH_USERS: | 
 | 4824 | 		case XPATH_POINT: | 
 | 4825 | 		case XPATH_RANGE: | 
 | 4826 | 		case XPATH_LOCATIONSET: | 
 | 4827 | 		    TODO | 
 | 4828 | 		    break; | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4829 | 		case XPATH_NODESET: | 
 | 4830 | 		case XPATH_XSLT_TREE: | 
 | 4831 | 		    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4832 | 	    } | 
 | 4833 | 	    break; | 
 | 4834 |         case XPATH_USERS: | 
 | 4835 | 	case XPATH_POINT: | 
 | 4836 | 	case XPATH_RANGE: | 
 | 4837 | 	case XPATH_LOCATIONSET: | 
 | 4838 | 	    TODO | 
 | 4839 | 	    break; | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4840 | 	case XPATH_NODESET: | 
 | 4841 | 	case XPATH_XSLT_TREE: | 
 | 4842 | 	    break; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 4843 |     } | 
 | 4844 |     xmlXPathFreeObject(arg1); | 
 | 4845 |     xmlXPathFreeObject(arg2); | 
 | 4846 |     return(ret); | 
 | 4847 | } | 
 | 4848 |  | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4849 | /** | 
 | 4850 |  * xmlXPathEqualValues: | 
 | 4851 |  * @ctxt:  the XPath Parser context | 
 | 4852 |  * | 
 | 4853 |  * Implement the equal operation on XPath objects content: @arg1 == @arg2 | 
 | 4854 |  * | 
 | 4855 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4856 |  */ | 
 | 4857 | int | 
 | 4858 | xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { | 
 | 4859 |     xmlXPathObjectPtr arg1, arg2, argtmp; | 
 | 4860 |     int ret = 0; | 
 | 4861 |  | 
 | 4862 |     arg2 = valuePop(ctxt);  | 
 | 4863 |     arg1 = valuePop(ctxt); | 
 | 4864 |     if ((arg1 == NULL) || (arg2 == NULL)) { | 
 | 4865 | 	if (arg1 != NULL) | 
 | 4866 | 	    xmlXPathFreeObject(arg1); | 
 | 4867 | 	else | 
 | 4868 | 	    xmlXPathFreeObject(arg2); | 
 | 4869 | 	XP_ERROR0(XPATH_INVALID_OPERAND); | 
 | 4870 |     } | 
 | 4871 |  | 
 | 4872 |     if (arg1 == arg2) { | 
 | 4873 | #ifdef DEBUG_EXPR | 
 | 4874 |         xmlGenericError(xmlGenericErrorContext, | 
 | 4875 | 		"Equal: by pointer\n"); | 
 | 4876 | #endif | 
 | 4877 |         return(1); | 
 | 4878 |     } | 
 | 4879 |  | 
 | 4880 |     /* | 
 | 4881 |      *If either argument is a nodeset, it's a 'special case' | 
 | 4882 |      */ | 
 | 4883 |     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || | 
 | 4884 |       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
 | 4885 | 	/* | 
 | 4886 | 	 *Hack it to assure arg1 is the nodeset | 
 | 4887 | 	 */ | 
 | 4888 | 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { | 
 | 4889 | 		argtmp = arg2; | 
 | 4890 | 		arg2 = arg1; | 
 | 4891 | 		arg1 = argtmp; | 
 | 4892 | 	} | 
 | 4893 | 	switch (arg2->type) { | 
 | 4894 | 	    case XPATH_UNDEFINED: | 
 | 4895 | #ifdef DEBUG_EXPR | 
 | 4896 | 		xmlGenericError(xmlGenericErrorContext, | 
 | 4897 | 			"Equal: undefined\n"); | 
 | 4898 | #endif | 
 | 4899 | 		break; | 
 | 4900 | 	    case XPATH_NODESET: | 
 | 4901 | 	    case XPATH_XSLT_TREE: | 
 | 4902 | 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0); | 
 | 4903 | 		break; | 
 | 4904 | 	    case XPATH_BOOLEAN: | 
 | 4905 | 		if ((arg1->nodesetval == NULL) || | 
 | 4906 | 		  (arg1->nodesetval->nodeNr == 0)) ret = 0; | 
 | 4907 | 		else  | 
 | 4908 | 		    ret = 1; | 
 | 4909 | 		ret = (ret == arg2->boolval); | 
 | 4910 | 		break; | 
 | 4911 | 	    case XPATH_NUMBER: | 
 | 4912 | 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); | 
 | 4913 | 		break; | 
 | 4914 | 	    case XPATH_STRING: | 
 | 4915 | 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); | 
 | 4916 | 		break; | 
 | 4917 | 	    case XPATH_USERS: | 
 | 4918 | 	    case XPATH_POINT: | 
 | 4919 | 	    case XPATH_RANGE: | 
 | 4920 | 	    case XPATH_LOCATIONSET: | 
 | 4921 | 		TODO | 
 | 4922 | 		break; | 
 | 4923 | 	} | 
 | 4924 | 	xmlXPathFreeObject(arg1); | 
 | 4925 | 	xmlXPathFreeObject(arg2); | 
 | 4926 | 	return(ret); | 
 | 4927 |     } | 
 | 4928 |  | 
 | 4929 |     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); | 
 | 4930 | } | 
 | 4931 |  | 
 | 4932 | /** | 
 | 4933 |  * xmlXPathNotEqualValues: | 
 | 4934 |  * @ctxt:  the XPath Parser context | 
 | 4935 |  * | 
 | 4936 |  * Implement the equal operation on XPath objects content: @arg1 == @arg2 | 
 | 4937 |  * | 
 | 4938 |  * Returns 0 or 1 depending on the results of the test. | 
 | 4939 |  */ | 
 | 4940 | int | 
 | 4941 | xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { | 
 | 4942 |     xmlXPathObjectPtr arg1, arg2, argtmp; | 
 | 4943 |     int ret = 0; | 
 | 4944 |  | 
 | 4945 |     arg2 = valuePop(ctxt);  | 
 | 4946 |     arg1 = valuePop(ctxt); | 
 | 4947 |     if ((arg1 == NULL) || (arg2 == NULL)) { | 
 | 4948 | 	if (arg1 != NULL) | 
 | 4949 | 	    xmlXPathFreeObject(arg1); | 
 | 4950 | 	else | 
 | 4951 | 	    xmlXPathFreeObject(arg2); | 
 | 4952 | 	XP_ERROR0(XPATH_INVALID_OPERAND); | 
 | 4953 |     } | 
 | 4954 |  | 
 | 4955 |     if (arg1 == arg2) { | 
 | 4956 | #ifdef DEBUG_EXPR | 
 | 4957 |         xmlGenericError(xmlGenericErrorContext, | 
 | 4958 | 		"NotEqual: by pointer\n"); | 
 | 4959 | #endif | 
 | 4960 |         return(0); | 
 | 4961 |     } | 
 | 4962 |  | 
 | 4963 |     /* | 
 | 4964 |      *If either argument is a nodeset, it's a 'special case' | 
 | 4965 |      */ | 
 | 4966 |     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || | 
 | 4967 |       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
 | 4968 | 	/* | 
 | 4969 | 	 *Hack it to assure arg1 is the nodeset | 
 | 4970 | 	 */ | 
 | 4971 | 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { | 
 | 4972 | 		argtmp = arg2; | 
 | 4973 | 		arg2 = arg1; | 
 | 4974 | 		arg1 = argtmp; | 
 | 4975 | 	} | 
 | 4976 | 	switch (arg2->type) { | 
 | 4977 | 	    case XPATH_UNDEFINED: | 
 | 4978 | #ifdef DEBUG_EXPR | 
 | 4979 | 		xmlGenericError(xmlGenericErrorContext, | 
 | 4980 | 			"NotEqual: undefined\n"); | 
 | 4981 | #endif | 
 | 4982 | 		break; | 
 | 4983 | 	    case XPATH_NODESET: | 
 | 4984 | 	    case XPATH_XSLT_TREE: | 
 | 4985 | 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1); | 
 | 4986 | 		break; | 
 | 4987 | 	    case XPATH_BOOLEAN: | 
 | 4988 | 		if ((arg1->nodesetval == NULL) || | 
 | 4989 | 		  (arg1->nodesetval->nodeNr == 0)) ret = 0; | 
 | 4990 | 		else  | 
 | 4991 | 		    ret = 1; | 
| William M. Brack | ef61d20 | 2002-07-19 08:32:00 +0000 | [diff] [blame] | 4992 | 		ret = (ret != arg2->boolval); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 4993 | 		break; | 
 | 4994 | 	    case XPATH_NUMBER: | 
 | 4995 | 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); | 
 | 4996 | 		break; | 
 | 4997 | 	    case XPATH_STRING: | 
 | 4998 | 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); | 
 | 4999 | 		break; | 
 | 5000 | 	    case XPATH_USERS: | 
 | 5001 | 	    case XPATH_POINT: | 
 | 5002 | 	    case XPATH_RANGE: | 
 | 5003 | 	    case XPATH_LOCATIONSET: | 
 | 5004 | 		TODO | 
 | 5005 | 		break; | 
 | 5006 | 	} | 
 | 5007 | 	xmlXPathFreeObject(arg1); | 
 | 5008 | 	xmlXPathFreeObject(arg2); | 
 | 5009 | 	return(ret); | 
 | 5010 |     } | 
 | 5011 |  | 
 | 5012 |     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); | 
 | 5013 | } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5014 |  | 
 | 5015 | /** | 
 | 5016 |  * xmlXPathCompareValues: | 
 | 5017 |  * @ctxt:  the XPath Parser context | 
 | 5018 |  * @inf:  less than (1) or greater than (0) | 
 | 5019 |  * @strict:  is the comparison strict | 
 | 5020 |  * | 
 | 5021 |  * Implement the compare operation on XPath objects:  | 
 | 5022 |  *     @arg1 < @arg2    (1, 1, ... | 
 | 5023 |  *     @arg1 <= @arg2   (1, 0, ... | 
 | 5024 |  *     @arg1 > @arg2    (0, 1, ... | 
 | 5025 |  *     @arg1 >= @arg2   (0, 0, ... | 
 | 5026 |  * | 
 | 5027 |  * When neither object to be compared is a node-set and the operator is | 
 | 5028 |  * <=, <, >=, >, then the objects are compared by converted both objects | 
 | 5029 |  * to numbers and comparing the numbers according to IEEE 754. The < | 
 | 5030 |  * comparison will be true if and only if the first number is less than the | 
 | 5031 |  * second number. The <= comparison will be true if and only if the first | 
 | 5032 |  * number is less than or equal to the second number. The > comparison | 
 | 5033 |  * will be true if and only if the first number is greater than the second | 
 | 5034 |  * number. The >= comparison will be true if and only if the first number | 
 | 5035 |  * is greater than or equal to the second number. | 
 | 5036 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 5037 |  * Returns 1 if the comparison succeeded, 0 if it failed | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5038 |  */ | 
 | 5039 | int | 
 | 5040 | xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 5041 |     int ret = 0, arg1i = 0, arg2i = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5042 |     xmlXPathObjectPtr arg1, arg2; | 
 | 5043 |  | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 5044 |     arg2 = valuePop(ctxt);  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5045 |     arg1 = valuePop(ctxt); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 5046 |     if ((arg1 == NULL) || (arg2 == NULL)) { | 
 | 5047 | 	if (arg1 != NULL) | 
 | 5048 | 	    xmlXPathFreeObject(arg1); | 
 | 5049 | 	else | 
 | 5050 | 	    xmlXPathFreeObject(arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5051 | 	XP_ERROR0(XPATH_INVALID_OPERAND); | 
 | 5052 |     } | 
 | 5053 |  | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 5054 |     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || | 
 | 5055 |       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
 | 5056 | 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && | 
 | 5057 | 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 5058 | 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5059 | 	} else { | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 5060 | 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
| Daniel Veillard | 4af6b6e | 2001-03-06 08:33:38 +0000 | [diff] [blame] | 5061 | 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, | 
 | 5062 | 			                          arg1, arg2); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5063 | 	    } else { | 
| Daniel Veillard | 4af6b6e | 2001-03-06 08:33:38 +0000 | [diff] [blame] | 5064 | 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, | 
 | 5065 | 			                          arg2, arg1); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5066 | 	    } | 
 | 5067 | 	} | 
 | 5068 | 	return(ret); | 
 | 5069 |     } | 
 | 5070 |  | 
 | 5071 |     if (arg1->type != XPATH_NUMBER) { | 
 | 5072 | 	valuePush(ctxt, arg1); | 
 | 5073 | 	xmlXPathNumberFunction(ctxt, 1); | 
 | 5074 | 	arg1 = valuePop(ctxt); | 
 | 5075 |     } | 
 | 5076 |     if (arg1->type != XPATH_NUMBER) { | 
 | 5077 | 	xmlXPathFreeObject(arg1); | 
 | 5078 | 	xmlXPathFreeObject(arg2); | 
 | 5079 | 	XP_ERROR0(XPATH_INVALID_OPERAND); | 
 | 5080 |     } | 
 | 5081 |     if (arg2->type != XPATH_NUMBER) { | 
 | 5082 | 	valuePush(ctxt, arg2); | 
 | 5083 | 	xmlXPathNumberFunction(ctxt, 1); | 
 | 5084 | 	arg2 = valuePop(ctxt); | 
 | 5085 |     } | 
 | 5086 |     if (arg2->type != XPATH_NUMBER) { | 
 | 5087 | 	xmlXPathFreeObject(arg1); | 
 | 5088 | 	xmlXPathFreeObject(arg2); | 
 | 5089 | 	XP_ERROR0(XPATH_INVALID_OPERAND); | 
 | 5090 |     } | 
 | 5091 |     /* | 
 | 5092 |      * Add tests for infinity and nan | 
 | 5093 |      * => feedback on 3.4 for Inf and NaN | 
 | 5094 |      */ | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 5095 |     /* Hand check NaN and Infinity comparisons */ | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 5096 |     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 5097 | 	ret=0; | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 5098 |     } else { | 
| Daniel Veillard | d30be4a | 2002-03-28 18:25:31 +0000 | [diff] [blame] | 5099 | 	arg1i=xmlXPathIsInf(arg1->floatval); | 
 | 5100 | 	arg2i=xmlXPathIsInf(arg2->floatval); | 
 | 5101 | 	if (inf && strict) { | 
 | 5102 | 	    if ((arg1i == -1 && arg2i != -1) || | 
 | 5103 | 		(arg2i == 1 && arg1i != 1)) { | 
 | 5104 | 		ret = 1; | 
 | 5105 | 	    } else if (arg1i == 0 && arg2i == 0) { | 
 | 5106 | 		ret = (arg1->floatval < arg2->floatval); | 
 | 5107 | 	    } else { | 
 | 5108 | 		ret = 0; | 
 | 5109 | 	    } | 
 | 5110 | 	} | 
 | 5111 | 	else if (inf && !strict) { | 
 | 5112 | 	    if (arg1i == -1 || arg2i == 1) { | 
 | 5113 | 		ret = 1; | 
 | 5114 | 	    } else if (arg1i == 0 && arg2i == 0) { | 
 | 5115 | 		ret = (arg1->floatval <= arg2->floatval); | 
 | 5116 | 	    } else { | 
 | 5117 | 		ret = 0; | 
 | 5118 | 	    } | 
 | 5119 | 	} | 
 | 5120 | 	else if (!inf && strict) { | 
 | 5121 | 	    if ((arg1i == 1 && arg2i != 1) || | 
 | 5122 | 		(arg2i == -1 && arg1i != -1)) { | 
 | 5123 | 		ret = 1; | 
 | 5124 | 	    } else if (arg1i == 0 && arg2i == 0) { | 
 | 5125 | 		ret = (arg1->floatval > arg2->floatval); | 
 | 5126 | 	    } else { | 
 | 5127 | 		ret = 0; | 
 | 5128 | 	    } | 
 | 5129 | 	} | 
 | 5130 | 	else if (!inf && !strict) { | 
 | 5131 | 	    if (arg1i == 1 || arg2i == -1) { | 
 | 5132 | 		ret = 1; | 
 | 5133 | 	    } else if (arg1i == 0 && arg2i == 0) { | 
 | 5134 | 		ret = (arg1->floatval >= arg2->floatval); | 
 | 5135 | 	    } else { | 
 | 5136 | 		ret = 0; | 
 | 5137 | 	    } | 
 | 5138 | 	} | 
| Daniel Veillard | 21458c8 | 2002-03-27 16:12:22 +0000 | [diff] [blame] | 5139 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5140 |     xmlXPathFreeObject(arg1); | 
 | 5141 |     xmlXPathFreeObject(arg2); | 
 | 5142 |     return(ret); | 
 | 5143 | } | 
 | 5144 |  | 
 | 5145 | /** | 
 | 5146 |  * xmlXPathValueFlipSign: | 
 | 5147 |  * @ctxt:  the XPath Parser context | 
 | 5148 |  * | 
 | 5149 |  * Implement the unary - operation on an XPath object | 
 | 5150 |  * The numeric operators convert their operands to numbers as if | 
 | 5151 |  * by calling the number function. | 
 | 5152 |  */ | 
 | 5153 | void | 
 | 5154 | xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5155 |     CAST_TO_NUMBER; | 
 | 5156 |     CHECK_TYPE(XPATH_NUMBER); | 
| Daniel Veillard | eca8281 | 2002-04-24 11:42:02 +0000 | [diff] [blame] | 5157 |     if (xmlXPathIsNaN(ctxt->value->floatval)) | 
 | 5158 |         ctxt->value->floatval=xmlXPathNAN; | 
 | 5159 |     else if (xmlXPathIsInf(ctxt->value->floatval) == 1) | 
 | 5160 |         ctxt->value->floatval=xmlXPathNINF; | 
 | 5161 |     else if (xmlXPathIsInf(ctxt->value->floatval) == -1) | 
 | 5162 |         ctxt->value->floatval=xmlXPathPINF; | 
 | 5163 |     else if (ctxt->value->floatval == 0) { | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 5164 |         if (xmlXPathGetSign(ctxt->value->floatval) == 0) | 
 | 5165 | 	    ctxt->value->floatval = xmlXPathNZERO; | 
 | 5166 | 	else | 
 | 5167 | 	    ctxt->value->floatval = 0; | 
 | 5168 |     } | 
 | 5169 |     else | 
 | 5170 |         ctxt->value->floatval = - ctxt->value->floatval; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5171 | } | 
 | 5172 |  | 
 | 5173 | /** | 
 | 5174 |  * xmlXPathAddValues: | 
 | 5175 |  * @ctxt:  the XPath Parser context | 
 | 5176 |  * | 
 | 5177 |  * Implement the add operation on XPath objects: | 
 | 5178 |  * The numeric operators convert their operands to numbers as if | 
 | 5179 |  * by calling the number function. | 
 | 5180 |  */ | 
 | 5181 | void | 
 | 5182 | xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { | 
 | 5183 |     xmlXPathObjectPtr arg; | 
 | 5184 |     double val; | 
 | 5185 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5186 |     arg = valuePop(ctxt); | 
 | 5187 |     if (arg == NULL) | 
 | 5188 | 	XP_ERROR(XPATH_INVALID_OPERAND); | 
 | 5189 |     val = xmlXPathCastToNumber(arg); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5190 |     xmlXPathFreeObject(arg); | 
 | 5191 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5192 |     CAST_TO_NUMBER; | 
 | 5193 |     CHECK_TYPE(XPATH_NUMBER); | 
 | 5194 |     ctxt->value->floatval += val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5195 | } | 
 | 5196 |  | 
 | 5197 | /** | 
 | 5198 |  * xmlXPathSubValues: | 
 | 5199 |  * @ctxt:  the XPath Parser context | 
 | 5200 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 5201 |  * Implement the subtraction operation on XPath objects: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5202 |  * The numeric operators convert their operands to numbers as if | 
 | 5203 |  * by calling the number function. | 
 | 5204 |  */ | 
 | 5205 | void | 
 | 5206 | xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { | 
 | 5207 |     xmlXPathObjectPtr arg; | 
 | 5208 |     double val; | 
 | 5209 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5210 |     arg = valuePop(ctxt); | 
 | 5211 |     if (arg == NULL) | 
 | 5212 | 	XP_ERROR(XPATH_INVALID_OPERAND); | 
 | 5213 |     val = xmlXPathCastToNumber(arg); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5214 |     xmlXPathFreeObject(arg); | 
 | 5215 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5216 |     CAST_TO_NUMBER; | 
 | 5217 |     CHECK_TYPE(XPATH_NUMBER); | 
 | 5218 |     ctxt->value->floatval -= val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5219 | } | 
 | 5220 |  | 
 | 5221 | /** | 
 | 5222 |  * xmlXPathMultValues: | 
 | 5223 |  * @ctxt:  the XPath Parser context | 
 | 5224 |  * | 
 | 5225 |  * Implement the multiply operation on XPath objects: | 
 | 5226 |  * The numeric operators convert their operands to numbers as if | 
 | 5227 |  * by calling the number function. | 
 | 5228 |  */ | 
 | 5229 | void | 
 | 5230 | xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { | 
 | 5231 |     xmlXPathObjectPtr arg; | 
 | 5232 |     double val; | 
 | 5233 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5234 |     arg = valuePop(ctxt); | 
 | 5235 |     if (arg == NULL) | 
 | 5236 | 	XP_ERROR(XPATH_INVALID_OPERAND); | 
 | 5237 |     val = xmlXPathCastToNumber(arg); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5238 |     xmlXPathFreeObject(arg); | 
 | 5239 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5240 |     CAST_TO_NUMBER; | 
 | 5241 |     CHECK_TYPE(XPATH_NUMBER); | 
 | 5242 |     ctxt->value->floatval *= val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5243 | } | 
 | 5244 |  | 
 | 5245 | /** | 
 | 5246 |  * xmlXPathDivValues: | 
 | 5247 |  * @ctxt:  the XPath Parser context | 
 | 5248 |  * | 
 | 5249 |  * Implement the div operation on XPath objects @arg1 / @arg2: | 
 | 5250 |  * The numeric operators convert their operands to numbers as if | 
 | 5251 |  * by calling the number function. | 
 | 5252 |  */ | 
 | 5253 | void | 
 | 5254 | xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { | 
 | 5255 |     xmlXPathObjectPtr arg; | 
 | 5256 |     double val; | 
 | 5257 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5258 |     arg = valuePop(ctxt); | 
 | 5259 |     if (arg == NULL) | 
 | 5260 | 	XP_ERROR(XPATH_INVALID_OPERAND); | 
 | 5261 |     val = xmlXPathCastToNumber(arg); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5262 |     xmlXPathFreeObject(arg); | 
 | 5263 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5264 |     CAST_TO_NUMBER; | 
 | 5265 |     CHECK_TYPE(XPATH_NUMBER); | 
| Daniel Veillard | eca8281 | 2002-04-24 11:42:02 +0000 | [diff] [blame] | 5266 |     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) | 
 | 5267 | 	ctxt->value->floatval = xmlXPathNAN; | 
 | 5268 |     else if (val == 0 && xmlXPathGetSign(val) != 0) { | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 5269 | 	if (ctxt->value->floatval == 0) | 
 | 5270 | 	    ctxt->value->floatval = xmlXPathNAN; | 
 | 5271 | 	else if (ctxt->value->floatval > 0) | 
 | 5272 | 	    ctxt->value->floatval = xmlXPathNINF; | 
 | 5273 | 	else if (ctxt->value->floatval < 0) | 
 | 5274 | 	    ctxt->value->floatval = xmlXPathPINF; | 
 | 5275 |     } | 
 | 5276 |     else if (val == 0) { | 
| Daniel Veillard | 5f4b599 | 2002-02-20 10:22:49 +0000 | [diff] [blame] | 5277 | 	if (ctxt->value->floatval == 0) | 
 | 5278 | 	    ctxt->value->floatval = xmlXPathNAN; | 
 | 5279 | 	else if (ctxt->value->floatval > 0) | 
 | 5280 | 	    ctxt->value->floatval = xmlXPathPINF; | 
 | 5281 | 	else if (ctxt->value->floatval < 0) | 
 | 5282 | 	    ctxt->value->floatval = xmlXPathNINF; | 
 | 5283 |     } else  | 
 | 5284 | 	ctxt->value->floatval /= val; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5285 | } | 
 | 5286 |  | 
 | 5287 | /** | 
 | 5288 |  * xmlXPathModValues: | 
 | 5289 |  * @ctxt:  the XPath Parser context | 
 | 5290 |  * | 
 | 5291 |  * Implement the mod operation on XPath objects: @arg1 / @arg2 | 
 | 5292 |  * The numeric operators convert their operands to numbers as if | 
 | 5293 |  * by calling the number function. | 
 | 5294 |  */ | 
 | 5295 | void | 
 | 5296 | xmlXPathModValues(xmlXPathParserContextPtr ctxt) { | 
 | 5297 |     xmlXPathObjectPtr arg; | 
| Daniel Veillard | fdc9156 | 2002-07-01 21:52:03 +0000 | [diff] [blame] | 5298 |     double arg1, arg2; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5299 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5300 |     arg = valuePop(ctxt); | 
 | 5301 |     if (arg == NULL) | 
 | 5302 | 	XP_ERROR(XPATH_INVALID_OPERAND); | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 5303 |     arg2 = xmlXPathCastToNumber(arg); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5304 |     xmlXPathFreeObject(arg); | 
 | 5305 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 5306 |     CAST_TO_NUMBER; | 
 | 5307 |     CHECK_TYPE(XPATH_NUMBER); | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 5308 |     arg1 = ctxt->value->floatval; | 
| Daniel Veillard | 268fd1b | 2001-08-26 18:46:36 +0000 | [diff] [blame] | 5309 |     if (arg2 == 0) | 
 | 5310 | 	ctxt->value->floatval = xmlXPathNAN; | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 5311 |     else { | 
| Daniel Veillard | fdc9156 | 2002-07-01 21:52:03 +0000 | [diff] [blame] | 5312 | 	ctxt->value->floatval = fmod(arg1, arg2); | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 5313 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5314 | } | 
 | 5315 |  | 
 | 5316 | /************************************************************************ | 
 | 5317 |  *									* | 
 | 5318 |  *		The traversal functions					* | 
 | 5319 |  *									* | 
 | 5320 |  ************************************************************************/ | 
 | 5321 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5322 | /* | 
 | 5323 |  * A traversal function enumerates nodes along an axis. | 
 | 5324 |  * Initially it must be called with NULL, and it indicates | 
 | 5325 |  * termination on the axis by returning NULL. | 
 | 5326 |  */ | 
 | 5327 | typedef xmlNodePtr (*xmlXPathTraversalFunction) | 
 | 5328 |                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); | 
 | 5329 |  | 
 | 5330 | /** | 
 | 5331 |  * xmlXPathNextSelf: | 
 | 5332 |  * @ctxt:  the XPath Parser context | 
 | 5333 |  * @cur:  the current node in the traversal | 
 | 5334 |  * | 
 | 5335 |  * Traversal function for the "self" direction | 
 | 5336 |  * The self axis contains just the context node itself | 
 | 5337 |  * | 
 | 5338 |  * Returns the next element following that axis | 
 | 5339 |  */ | 
 | 5340 | xmlNodePtr | 
 | 5341 | xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5342 |     if (cur == NULL) | 
 | 5343 |         return(ctxt->context->node); | 
 | 5344 |     return(NULL); | 
 | 5345 | } | 
 | 5346 |  | 
 | 5347 | /** | 
 | 5348 |  * xmlXPathNextChild: | 
 | 5349 |  * @ctxt:  the XPath Parser context | 
 | 5350 |  * @cur:  the current node in the traversal | 
 | 5351 |  * | 
 | 5352 |  * Traversal function for the "child" direction | 
 | 5353 |  * The child axis contains the children of the context node in document order. | 
 | 5354 |  * | 
 | 5355 |  * Returns the next element following that axis | 
 | 5356 |  */ | 
 | 5357 | xmlNodePtr | 
 | 5358 | xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5359 |     if (cur == NULL) { | 
 | 5360 | 	if (ctxt->context->node == NULL) return(NULL); | 
 | 5361 | 	switch (ctxt->context->node->type) { | 
 | 5362 |             case XML_ELEMENT_NODE: | 
 | 5363 |             case XML_TEXT_NODE: | 
 | 5364 |             case XML_CDATA_SECTION_NODE: | 
 | 5365 |             case XML_ENTITY_REF_NODE: | 
 | 5366 |             case XML_ENTITY_NODE: | 
 | 5367 |             case XML_PI_NODE: | 
 | 5368 |             case XML_COMMENT_NODE: | 
 | 5369 |             case XML_NOTATION_NODE: | 
 | 5370 |             case XML_DTD_NODE: | 
 | 5371 | 		return(ctxt->context->node->children); | 
 | 5372 |             case XML_DOCUMENT_NODE: | 
 | 5373 |             case XML_DOCUMENT_TYPE_NODE: | 
 | 5374 |             case XML_DOCUMENT_FRAG_NODE: | 
 | 5375 |             case XML_HTML_DOCUMENT_NODE: | 
| Daniel Veillard | eae522a | 2001-04-23 13:41:34 +0000 | [diff] [blame] | 5376 | #ifdef LIBXML_DOCB_ENABLED | 
 | 5377 | 	    case XML_DOCB_DOCUMENT_NODE: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5378 | #endif | 
 | 5379 | 		return(((xmlDocPtr) ctxt->context->node)->children); | 
 | 5380 | 	    case XML_ELEMENT_DECL: | 
 | 5381 | 	    case XML_ATTRIBUTE_DECL: | 
 | 5382 | 	    case XML_ENTITY_DECL: | 
 | 5383 |             case XML_ATTRIBUTE_NODE: | 
 | 5384 | 	    case XML_NAMESPACE_DECL: | 
 | 5385 | 	    case XML_XINCLUDE_START: | 
 | 5386 | 	    case XML_XINCLUDE_END: | 
 | 5387 | 		return(NULL); | 
 | 5388 | 	} | 
 | 5389 | 	return(NULL); | 
 | 5390 |     } | 
 | 5391 |     if ((cur->type == XML_DOCUMENT_NODE) || | 
 | 5392 |         (cur->type == XML_HTML_DOCUMENT_NODE)) | 
 | 5393 | 	return(NULL); | 
 | 5394 |     return(cur->next); | 
 | 5395 | } | 
 | 5396 |  | 
 | 5397 | /** | 
 | 5398 |  * xmlXPathNextDescendant: | 
 | 5399 |  * @ctxt:  the XPath Parser context | 
 | 5400 |  * @cur:  the current node in the traversal | 
 | 5401 |  * | 
 | 5402 |  * Traversal function for the "descendant" direction | 
 | 5403 |  * the descendant axis contains the descendants of the context node in document | 
 | 5404 |  * order; a descendant is a child or a child of a child and so on. | 
 | 5405 |  * | 
 | 5406 |  * Returns the next element following that axis | 
 | 5407 |  */ | 
 | 5408 | xmlNodePtr | 
 | 5409 | xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5410 |     if (cur == NULL) { | 
 | 5411 | 	if (ctxt->context->node == NULL) | 
 | 5412 | 	    return(NULL); | 
 | 5413 | 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || | 
 | 5414 | 	    (ctxt->context->node->type == XML_NAMESPACE_DECL)) | 
 | 5415 | 	    return(NULL); | 
 | 5416 |  | 
 | 5417 |         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) | 
 | 5418 | 	    return(ctxt->context->doc->children); | 
 | 5419 |         return(ctxt->context->node->children); | 
 | 5420 |     } | 
 | 5421 |  | 
| Daniel Veillard | 567e1b4 | 2001-08-01 15:53:47 +0000 | [diff] [blame] | 5422 |     if (cur->children != NULL) { | 
| Daniel Veillard | 68e9e74 | 2002-11-16 15:35:11 +0000 | [diff] [blame] | 5423 | 	/* | 
 | 5424 | 	 * Do not descend on entities declarations | 
 | 5425 | 	 */ | 
 | 5426 |     	if (cur->children->type != XML_ENTITY_DECL) { | 
 | 5427 | 	    cur = cur->children; | 
 | 5428 | 	    /* | 
 | 5429 | 	     * Skip DTDs | 
 | 5430 | 	     */ | 
 | 5431 | 	    if (cur->type != XML_DTD_NODE) | 
 | 5432 | 		return(cur); | 
 | 5433 | 	} | 
| Daniel Veillard | 567e1b4 | 2001-08-01 15:53:47 +0000 | [diff] [blame] | 5434 |     } | 
 | 5435 |  | 
 | 5436 |     if (cur == ctxt->context->node) return(NULL); | 
 | 5437 |  | 
| Daniel Veillard | 68e9e74 | 2002-11-16 15:35:11 +0000 | [diff] [blame] | 5438 |     while (cur->next != NULL) { | 
 | 5439 | 	cur = cur->next; | 
 | 5440 | 	if ((cur->type != XML_ENTITY_DECL) && | 
 | 5441 | 	    (cur->type != XML_DTD_NODE)) | 
 | 5442 | 	    return(cur); | 
 | 5443 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5444 |      | 
 | 5445 |     do { | 
 | 5446 |         cur = cur->parent; | 
 | 5447 | 	if (cur == NULL) return(NULL); | 
 | 5448 | 	if (cur == ctxt->context->node) return(NULL); | 
 | 5449 | 	if (cur->next != NULL) { | 
 | 5450 | 	    cur = cur->next; | 
 | 5451 | 	    return(cur); | 
 | 5452 | 	} | 
 | 5453 |     } while (cur != NULL); | 
 | 5454 |     return(cur); | 
 | 5455 | } | 
 | 5456 |  | 
 | 5457 | /** | 
 | 5458 |  * xmlXPathNextDescendantOrSelf: | 
 | 5459 |  * @ctxt:  the XPath Parser context | 
 | 5460 |  * @cur:  the current node in the traversal | 
 | 5461 |  * | 
 | 5462 |  * Traversal function for the "descendant-or-self" direction | 
 | 5463 |  * the descendant-or-self axis contains the context node and the descendants | 
 | 5464 |  * of the context node in document order; thus the context node is the first | 
 | 5465 |  * node on the axis, and the first child of the context node is the second node | 
 | 5466 |  * on the axis | 
 | 5467 |  * | 
 | 5468 |  * Returns the next element following that axis | 
 | 5469 |  */ | 
 | 5470 | xmlNodePtr | 
 | 5471 | xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5472 |     if (cur == NULL) { | 
 | 5473 | 	if (ctxt->context->node == NULL) | 
 | 5474 | 	    return(NULL); | 
 | 5475 | 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || | 
 | 5476 | 	    (ctxt->context->node->type == XML_NAMESPACE_DECL)) | 
 | 5477 | 	    return(NULL); | 
 | 5478 |         return(ctxt->context->node); | 
 | 5479 |     } | 
 | 5480 |  | 
 | 5481 |     return(xmlXPathNextDescendant(ctxt, cur)); | 
 | 5482 | } | 
 | 5483 |  | 
 | 5484 | /** | 
 | 5485 |  * xmlXPathNextParent: | 
 | 5486 |  * @ctxt:  the XPath Parser context | 
 | 5487 |  * @cur:  the current node in the traversal | 
 | 5488 |  * | 
 | 5489 |  * Traversal function for the "parent" direction | 
 | 5490 |  * The parent axis contains the parent of the context node, if there is one. | 
 | 5491 |  * | 
 | 5492 |  * Returns the next element following that axis | 
 | 5493 |  */ | 
 | 5494 | xmlNodePtr | 
 | 5495 | xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5496 |     /* | 
 | 5497 |      * the parent of an attribute or namespace node is the element | 
 | 5498 |      * to which the attribute or namespace node is attached | 
 | 5499 |      * Namespace handling !!! | 
 | 5500 |      */ | 
 | 5501 |     if (cur == NULL) { | 
 | 5502 | 	if (ctxt->context->node == NULL) return(NULL); | 
 | 5503 | 	switch (ctxt->context->node->type) { | 
 | 5504 |             case XML_ELEMENT_NODE: | 
 | 5505 |             case XML_TEXT_NODE: | 
 | 5506 |             case XML_CDATA_SECTION_NODE: | 
 | 5507 |             case XML_ENTITY_REF_NODE: | 
 | 5508 |             case XML_ENTITY_NODE: | 
 | 5509 |             case XML_PI_NODE: | 
 | 5510 |             case XML_COMMENT_NODE: | 
 | 5511 |             case XML_NOTATION_NODE: | 
 | 5512 |             case XML_DTD_NODE: | 
 | 5513 | 	    case XML_ELEMENT_DECL: | 
 | 5514 | 	    case XML_ATTRIBUTE_DECL: | 
 | 5515 | 	    case XML_XINCLUDE_START: | 
 | 5516 | 	    case XML_XINCLUDE_END: | 
 | 5517 | 	    case XML_ENTITY_DECL: | 
 | 5518 | 		if (ctxt->context->node->parent == NULL) | 
 | 5519 | 		    return((xmlNodePtr) ctxt->context->doc); | 
| Daniel Veillard | 8e7e1c0 | 2003-01-10 17:06:09 +0000 | [diff] [blame] | 5520 | 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 5521 | 		    ((ctxt->context->node->parent->name[0] == ' ') || | 
 | 5522 | 		     (xmlStrEqual(ctxt->context->node->parent->name, | 
 | 5523 | 				 BAD_CAST "fake node libxslt")))) | 
| Daniel Veillard | 8e7e1c0 | 2003-01-10 17:06:09 +0000 | [diff] [blame] | 5524 | 		    return(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5525 | 		return(ctxt->context->node->parent); | 
 | 5526 |             case XML_ATTRIBUTE_NODE: { | 
 | 5527 | 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; | 
 | 5528 |  | 
 | 5529 | 		return(att->parent); | 
 | 5530 | 	    } | 
 | 5531 |             case XML_DOCUMENT_NODE: | 
 | 5532 |             case XML_DOCUMENT_TYPE_NODE: | 
 | 5533 |             case XML_DOCUMENT_FRAG_NODE: | 
 | 5534 |             case XML_HTML_DOCUMENT_NODE: | 
| Daniel Veillard | eae522a | 2001-04-23 13:41:34 +0000 | [diff] [blame] | 5535 | #ifdef LIBXML_DOCB_ENABLED | 
 | 5536 | 	    case XML_DOCB_DOCUMENT_NODE: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5537 | #endif | 
 | 5538 |                 return(NULL); | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 5539 | 	    case XML_NAMESPACE_DECL: { | 
 | 5540 | 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; | 
 | 5541 | 		 | 
 | 5542 | 		if ((ns->next != NULL) && | 
 | 5543 | 		    (ns->next->type != XML_NAMESPACE_DECL)) | 
 | 5544 | 		    return((xmlNodePtr) ns->next); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5545 |                 return(NULL); | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 5546 | 	    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5547 | 	} | 
 | 5548 |     } | 
 | 5549 |     return(NULL); | 
 | 5550 | } | 
 | 5551 |  | 
 | 5552 | /** | 
 | 5553 |  * xmlXPathNextAncestor: | 
 | 5554 |  * @ctxt:  the XPath Parser context | 
 | 5555 |  * @cur:  the current node in the traversal | 
 | 5556 |  * | 
 | 5557 |  * Traversal function for the "ancestor" direction | 
 | 5558 |  * the ancestor axis contains the ancestors of the context node; the ancestors | 
 | 5559 |  * of the context node consist of the parent of context node and the parent's | 
 | 5560 |  * parent and so on; the nodes are ordered in reverse document order; thus the | 
 | 5561 |  * parent is the first node on the axis, and the parent's parent is the second | 
 | 5562 |  * node on the axis | 
 | 5563 |  * | 
 | 5564 |  * Returns the next element following that axis | 
 | 5565 |  */ | 
 | 5566 | xmlNodePtr | 
 | 5567 | xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5568 |     /* | 
 | 5569 |      * the parent of an attribute or namespace node is the element | 
 | 5570 |      * to which the attribute or namespace node is attached | 
 | 5571 |      * !!!!!!!!!!!!! | 
 | 5572 |      */ | 
 | 5573 |     if (cur == NULL) { | 
 | 5574 | 	if (ctxt->context->node == NULL) return(NULL); | 
 | 5575 | 	switch (ctxt->context->node->type) { | 
 | 5576 |             case XML_ELEMENT_NODE: | 
 | 5577 |             case XML_TEXT_NODE: | 
 | 5578 |             case XML_CDATA_SECTION_NODE: | 
 | 5579 |             case XML_ENTITY_REF_NODE: | 
 | 5580 |             case XML_ENTITY_NODE: | 
 | 5581 |             case XML_PI_NODE: | 
 | 5582 |             case XML_COMMENT_NODE: | 
 | 5583 | 	    case XML_DTD_NODE: | 
 | 5584 | 	    case XML_ELEMENT_DECL: | 
 | 5585 | 	    case XML_ATTRIBUTE_DECL: | 
 | 5586 | 	    case XML_ENTITY_DECL: | 
 | 5587 |             case XML_NOTATION_NODE: | 
 | 5588 | 	    case XML_XINCLUDE_START: | 
 | 5589 | 	    case XML_XINCLUDE_END: | 
 | 5590 | 		if (ctxt->context->node->parent == NULL) | 
 | 5591 | 		    return((xmlNodePtr) ctxt->context->doc); | 
| Daniel Veillard | 8e7e1c0 | 2003-01-10 17:06:09 +0000 | [diff] [blame] | 5592 | 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 5593 | 		    ((ctxt->context->node->parent->name[0] == ' ') || | 
 | 5594 | 		     (xmlStrEqual(ctxt->context->node->parent->name, | 
 | 5595 | 				 BAD_CAST "fake node libxslt")))) | 
| Daniel Veillard | 8e7e1c0 | 2003-01-10 17:06:09 +0000 | [diff] [blame] | 5596 | 		    return(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5597 | 		return(ctxt->context->node->parent); | 
 | 5598 |             case XML_ATTRIBUTE_NODE: { | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 5599 | 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5600 |  | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 5601 | 		return(tmp->parent); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5602 | 	    } | 
 | 5603 |             case XML_DOCUMENT_NODE: | 
 | 5604 |             case XML_DOCUMENT_TYPE_NODE: | 
 | 5605 |             case XML_DOCUMENT_FRAG_NODE: | 
 | 5606 |             case XML_HTML_DOCUMENT_NODE: | 
| Daniel Veillard | eae522a | 2001-04-23 13:41:34 +0000 | [diff] [blame] | 5607 | #ifdef LIBXML_DOCB_ENABLED | 
 | 5608 | 	    case XML_DOCB_DOCUMENT_NODE: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5609 | #endif | 
 | 5610 |                 return(NULL); | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 5611 | 	    case XML_NAMESPACE_DECL: { | 
 | 5612 | 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; | 
 | 5613 | 		 | 
 | 5614 | 		if ((ns->next != NULL) && | 
 | 5615 | 		    (ns->next->type != XML_NAMESPACE_DECL)) | 
 | 5616 | 		    return((xmlNodePtr) ns->next); | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 5617 | 		/* Bad, how did that namespace end up here ? */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5618 |                 return(NULL); | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 5619 | 	    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5620 | 	} | 
 | 5621 | 	return(NULL); | 
 | 5622 |     } | 
 | 5623 |     if (cur == ctxt->context->doc->children) | 
 | 5624 | 	return((xmlNodePtr) ctxt->context->doc); | 
 | 5625 |     if (cur == (xmlNodePtr) ctxt->context->doc) | 
 | 5626 | 	return(NULL); | 
 | 5627 |     switch (cur->type) { | 
 | 5628 | 	case XML_ELEMENT_NODE: | 
 | 5629 | 	case XML_TEXT_NODE: | 
 | 5630 | 	case XML_CDATA_SECTION_NODE: | 
 | 5631 | 	case XML_ENTITY_REF_NODE: | 
 | 5632 | 	case XML_ENTITY_NODE: | 
 | 5633 | 	case XML_PI_NODE: | 
 | 5634 | 	case XML_COMMENT_NODE: | 
 | 5635 | 	case XML_NOTATION_NODE: | 
 | 5636 | 	case XML_DTD_NODE: | 
 | 5637 |         case XML_ELEMENT_DECL: | 
 | 5638 |         case XML_ATTRIBUTE_DECL: | 
 | 5639 |         case XML_ENTITY_DECL: | 
 | 5640 | 	case XML_XINCLUDE_START: | 
 | 5641 | 	case XML_XINCLUDE_END: | 
| Daniel Veillard | 8e7e1c0 | 2003-01-10 17:06:09 +0000 | [diff] [blame] | 5642 | 	    if (cur->parent == NULL) | 
 | 5643 | 		return(NULL); | 
 | 5644 | 	    if ((cur->parent->type == XML_ELEMENT_NODE) && | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 5645 | 		((cur->parent->name[0] == ' ') || | 
 | 5646 | 		 (xmlStrEqual(cur->parent->name, | 
 | 5647 | 			      BAD_CAST "fake node libxslt")))) | 
| Daniel Veillard | 8e7e1c0 | 2003-01-10 17:06:09 +0000 | [diff] [blame] | 5648 | 		return(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5649 | 	    return(cur->parent); | 
 | 5650 | 	case XML_ATTRIBUTE_NODE: { | 
 | 5651 | 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; | 
 | 5652 |  | 
 | 5653 | 	    return(att->parent); | 
 | 5654 | 	} | 
| Aleksey Sanin | dffd5c8 | 2002-05-31 04:24:13 +0000 | [diff] [blame] | 5655 | 	case XML_NAMESPACE_DECL: { | 
 | 5656 | 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; | 
 | 5657 | 		 | 
 | 5658 | 	    if ((ns->next != NULL) && | 
 | 5659 | 	        (ns->next->type != XML_NAMESPACE_DECL)) | 
 | 5660 | 	        return((xmlNodePtr) ns->next); | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 5661 | 	    /* Bad, how did that namespace end up here ? */ | 
| Aleksey Sanin | dffd5c8 | 2002-05-31 04:24:13 +0000 | [diff] [blame] | 5662 |             return(NULL); | 
 | 5663 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5664 | 	case XML_DOCUMENT_NODE: | 
 | 5665 | 	case XML_DOCUMENT_TYPE_NODE: | 
 | 5666 | 	case XML_DOCUMENT_FRAG_NODE: | 
 | 5667 | 	case XML_HTML_DOCUMENT_NODE: | 
| Daniel Veillard | eae522a | 2001-04-23 13:41:34 +0000 | [diff] [blame] | 5668 | #ifdef LIBXML_DOCB_ENABLED | 
 | 5669 | 	case XML_DOCB_DOCUMENT_NODE: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5670 | #endif | 
 | 5671 | 	    return(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5672 |     } | 
 | 5673 |     return(NULL); | 
 | 5674 | } | 
 | 5675 |  | 
 | 5676 | /** | 
 | 5677 |  * xmlXPathNextAncestorOrSelf: | 
 | 5678 |  * @ctxt:  the XPath Parser context | 
 | 5679 |  * @cur:  the current node in the traversal | 
 | 5680 |  * | 
 | 5681 |  * Traversal function for the "ancestor-or-self" direction | 
 | 5682 |  * he ancestor-or-self axis contains the context node and ancestors of | 
 | 5683 |  * the context node in reverse document order; thus the context node is | 
 | 5684 |  * the first node on the axis, and the context node's parent the second; | 
 | 5685 |  * parent here is defined the same as with the parent axis. | 
 | 5686 |  * | 
 | 5687 |  * Returns the next element following that axis | 
 | 5688 |  */ | 
 | 5689 | xmlNodePtr | 
 | 5690 | xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5691 |     if (cur == NULL) | 
 | 5692 |         return(ctxt->context->node); | 
 | 5693 |     return(xmlXPathNextAncestor(ctxt, cur)); | 
 | 5694 | } | 
 | 5695 |  | 
 | 5696 | /** | 
 | 5697 |  * xmlXPathNextFollowingSibling: | 
 | 5698 |  * @ctxt:  the XPath Parser context | 
 | 5699 |  * @cur:  the current node in the traversal | 
 | 5700 |  * | 
 | 5701 |  * Traversal function for the "following-sibling" direction | 
 | 5702 |  * The following-sibling axis contains the following siblings of the context | 
 | 5703 |  * node in document order. | 
 | 5704 |  * | 
 | 5705 |  * Returns the next element following that axis | 
 | 5706 |  */ | 
 | 5707 | xmlNodePtr | 
 | 5708 | xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5709 |     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || | 
 | 5710 | 	(ctxt->context->node->type == XML_NAMESPACE_DECL)) | 
 | 5711 | 	return(NULL); | 
 | 5712 |     if (cur == (xmlNodePtr) ctxt->context->doc) | 
 | 5713 |         return(NULL); | 
 | 5714 |     if (cur == NULL) | 
 | 5715 |         return(ctxt->context->node->next); | 
 | 5716 |     return(cur->next); | 
 | 5717 | } | 
 | 5718 |  | 
 | 5719 | /** | 
 | 5720 |  * xmlXPathNextPrecedingSibling: | 
 | 5721 |  * @ctxt:  the XPath Parser context | 
 | 5722 |  * @cur:  the current node in the traversal | 
 | 5723 |  * | 
 | 5724 |  * Traversal function for the "preceding-sibling" direction | 
 | 5725 |  * The preceding-sibling axis contains the preceding siblings of the context | 
 | 5726 |  * node in reverse document order; the first preceding sibling is first on the | 
 | 5727 |  * axis; the sibling preceding that node is the second on the axis and so on. | 
 | 5728 |  * | 
 | 5729 |  * Returns the next element following that axis | 
 | 5730 |  */ | 
 | 5731 | xmlNodePtr | 
 | 5732 | xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5733 |     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || | 
 | 5734 | 	(ctxt->context->node->type == XML_NAMESPACE_DECL)) | 
 | 5735 | 	return(NULL); | 
 | 5736 |     if (cur == (xmlNodePtr) ctxt->context->doc) | 
 | 5737 |         return(NULL); | 
 | 5738 |     if (cur == NULL) | 
 | 5739 |         return(ctxt->context->node->prev); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 5740 |     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { | 
 | 5741 | 	cur = cur->prev; | 
 | 5742 | 	if (cur == NULL) | 
 | 5743 | 	    return(ctxt->context->node->prev); | 
 | 5744 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5745 |     return(cur->prev); | 
 | 5746 | } | 
 | 5747 |  | 
 | 5748 | /** | 
 | 5749 |  * xmlXPathNextFollowing: | 
 | 5750 |  * @ctxt:  the XPath Parser context | 
 | 5751 |  * @cur:  the current node in the traversal | 
 | 5752 |  * | 
 | 5753 |  * Traversal function for the "following" direction | 
 | 5754 |  * The following axis contains all nodes in the same document as the context | 
 | 5755 |  * node that are after the context node in document order, excluding any | 
 | 5756 |  * descendants and excluding attribute nodes and namespace nodes; the nodes | 
 | 5757 |  * are ordered in document order | 
 | 5758 |  * | 
 | 5759 |  * Returns the next element following that axis | 
 | 5760 |  */ | 
 | 5761 | xmlNodePtr | 
 | 5762 | xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5763 |     if (cur != NULL && cur->children != NULL) | 
 | 5764 |         return cur->children ; | 
 | 5765 |     if (cur == NULL) cur = ctxt->context->node; | 
 | 5766 |     if (cur == NULL) return(NULL) ; /* ERROR */ | 
 | 5767 |     if (cur->next != NULL) return(cur->next) ; | 
 | 5768 |     do { | 
 | 5769 |         cur = cur->parent; | 
 | 5770 |         if (cur == NULL) return(NULL); | 
 | 5771 |         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); | 
 | 5772 |         if (cur->next != NULL) return(cur->next); | 
 | 5773 |     } while (cur != NULL); | 
 | 5774 |     return(cur); | 
 | 5775 | } | 
 | 5776 |  | 
 | 5777 | /* | 
 | 5778 |  * xmlXPathIsAncestor: | 
 | 5779 |  * @ancestor:  the ancestor node | 
 | 5780 |  * @node:  the current node | 
 | 5781 |  * | 
 | 5782 |  * Check that @ancestor is a @node's ancestor | 
 | 5783 |  * | 
 | 5784 |  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. | 
 | 5785 |  */ | 
 | 5786 | static int | 
 | 5787 | xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { | 
 | 5788 |     if ((ancestor == NULL) || (node == NULL)) return(0); | 
 | 5789 |     /* nodes need to be in the same document */ | 
 | 5790 |     if (ancestor->doc != node->doc) return(0); | 
 | 5791 |     /* avoid searching if ancestor or node is the root node */ | 
 | 5792 |     if (ancestor == (xmlNodePtr) node->doc) return(1); | 
 | 5793 |     if (node == (xmlNodePtr) ancestor->doc) return(0); | 
 | 5794 |     while (node->parent != NULL) { | 
 | 5795 |         if (node->parent == ancestor) | 
 | 5796 |             return(1); | 
 | 5797 | 	node = node->parent; | 
 | 5798 |     } | 
 | 5799 |     return(0); | 
 | 5800 | } | 
 | 5801 |  | 
 | 5802 | /** | 
 | 5803 |  * xmlXPathNextPreceding: | 
 | 5804 |  * @ctxt:  the XPath Parser context | 
 | 5805 |  * @cur:  the current node in the traversal | 
 | 5806 |  * | 
 | 5807 |  * Traversal function for the "preceding" direction | 
 | 5808 |  * the preceding axis contains all nodes in the same document as the context | 
 | 5809 |  * node that are before the context node in document order, excluding any | 
 | 5810 |  * ancestors and excluding attribute nodes and namespace nodes; the nodes are | 
 | 5811 |  * ordered in reverse document order | 
 | 5812 |  * | 
 | 5813 |  * Returns the next element following that axis | 
 | 5814 |  */ | 
 | 5815 | xmlNodePtr | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 5816 | xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) | 
 | 5817 | { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5818 |     if (cur == NULL) | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 5819 |         cur = ctxt->context->node; | 
 | 5820 |     if (cur == NULL) | 
 | 5821 | 	return (NULL); | 
 | 5822 |     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) | 
 | 5823 | 	cur = cur->prev; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5824 |     do { | 
 | 5825 |         if (cur->prev != NULL) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 5826 |             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; | 
 | 5827 |             return (cur); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5828 |         } | 
 | 5829 |  | 
 | 5830 |         cur = cur->parent; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 5831 |         if (cur == NULL) | 
 | 5832 |             return (NULL); | 
 | 5833 |         if (cur == ctxt->context->doc->children) | 
 | 5834 |             return (NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5835 |     } while (xmlXPathIsAncestor(cur, ctxt->context->node)); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 5836 |     return (cur); | 
 | 5837 | } | 
 | 5838 |  | 
 | 5839 | /** | 
 | 5840 |  * xmlXPathNextPrecedingInternal: | 
 | 5841 |  * @ctxt:  the XPath Parser context | 
 | 5842 |  * @cur:  the current node in the traversal | 
 | 5843 |  * | 
 | 5844 |  * Traversal function for the "preceding" direction | 
 | 5845 |  * the preceding axis contains all nodes in the same document as the context | 
 | 5846 |  * node that are before the context node in document order, excluding any | 
 | 5847 |  * ancestors and excluding attribute nodes and namespace nodes; the nodes are | 
 | 5848 |  * ordered in reverse document order | 
 | 5849 |  * This is a faster implementation but internal only since it requires a  | 
 | 5850 |  * state kept in the parser context: ctxt->ancestor. | 
 | 5851 |  * | 
 | 5852 |  * Returns the next element following that axis | 
 | 5853 |  */ | 
 | 5854 | static xmlNodePtr | 
 | 5855 | xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, | 
 | 5856 |                               xmlNodePtr cur) | 
 | 5857 | { | 
 | 5858 |     if (cur == NULL) { | 
 | 5859 |         cur = ctxt->context->node; | 
 | 5860 |         if (cur == NULL) | 
 | 5861 |             return (NULL); | 
| William M. Brack | 40c22b4 | 2003-10-10 03:58:39 +0000 | [diff] [blame] | 5862 | 	if (cur->type == XML_NAMESPACE_DECL) | 
 | 5863 | 	    cur = (xmlNodePtr)((xmlNsPtr)cur)->next; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 5864 |         ctxt->ancestor = cur->parent; | 
 | 5865 |     } | 
 | 5866 |     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) | 
 | 5867 | 	cur = cur->prev; | 
 | 5868 |     while (cur->prev == NULL) { | 
 | 5869 |         cur = cur->parent; | 
 | 5870 |         if (cur == NULL) | 
 | 5871 |             return (NULL); | 
 | 5872 |         if (cur == ctxt->context->doc->children) | 
 | 5873 |             return (NULL); | 
 | 5874 |         if (cur != ctxt->ancestor) | 
 | 5875 |             return (cur); | 
 | 5876 |         ctxt->ancestor = cur->parent; | 
 | 5877 |     } | 
 | 5878 |     cur = cur->prev; | 
 | 5879 |     while (cur->last != NULL) | 
 | 5880 |         cur = cur->last; | 
 | 5881 |     return (cur); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5882 | } | 
 | 5883 |  | 
 | 5884 | /** | 
 | 5885 |  * xmlXPathNextNamespace: | 
 | 5886 |  * @ctxt:  the XPath Parser context | 
 | 5887 |  * @cur:  the current attribute in the traversal | 
 | 5888 |  * | 
 | 5889 |  * Traversal function for the "namespace" direction | 
 | 5890 |  * the namespace axis contains the namespace nodes of the context node; | 
 | 5891 |  * the order of nodes on this axis is implementation-defined; the axis will | 
 | 5892 |  * be empty unless the context node is an element | 
 | 5893 |  * | 
| Daniel Veillard | 20ee8c0 | 2001-10-05 09:18:14 +0000 | [diff] [blame] | 5894 |  * We keep the XML namespace node at the end of the list. | 
 | 5895 |  * | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5896 |  * Returns the next element following that axis | 
 | 5897 |  */ | 
 | 5898 | xmlNodePtr | 
 | 5899 | xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
 | 5900 |     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); | 
| Daniel Veillard | fdc9156 | 2002-07-01 21:52:03 +0000 | [diff] [blame] | 5901 |     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { | 
| Daniel Veillard | 7d7e379 | 2001-07-30 13:42:13 +0000 | [diff] [blame] | 5902 |         if (ctxt->context->tmpNsList != NULL) | 
 | 5903 | 	    xmlFree(ctxt->context->tmpNsList); | 
 | 5904 | 	ctxt->context->tmpNsList =  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5905 | 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node); | 
| Daniel Veillard | 7d7e379 | 2001-07-30 13:42:13 +0000 | [diff] [blame] | 5906 | 	ctxt->context->tmpNsNr = 0; | 
| Daniel Veillard | fdc9156 | 2002-07-01 21:52:03 +0000 | [diff] [blame] | 5907 | 	if (ctxt->context->tmpNsList != NULL) { | 
 | 5908 | 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { | 
 | 5909 | 		ctxt->context->tmpNsNr++; | 
 | 5910 | 	    } | 
 | 5911 | 	} | 
| Daniel Veillard | 20ee8c0 | 2001-10-05 09:18:14 +0000 | [diff] [blame] | 5912 | 	return((xmlNodePtr) xmlXPathXMLNamespace); | 
| Daniel Veillard | 7d7e379 | 2001-07-30 13:42:13 +0000 | [diff] [blame] | 5913 |     } | 
| Daniel Veillard | fdc9156 | 2002-07-01 21:52:03 +0000 | [diff] [blame] | 5914 |     if (ctxt->context->tmpNsNr > 0) { | 
 | 5915 | 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; | 
 | 5916 |     } else { | 
 | 5917 | 	if (ctxt->context->tmpNsList != NULL) | 
 | 5918 | 	    xmlFree(ctxt->context->tmpNsList); | 
 | 5919 | 	ctxt->context->tmpNsList = NULL; | 
 | 5920 | 	return(NULL); | 
 | 5921 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5922 | } | 
 | 5923 |  | 
 | 5924 | /** | 
 | 5925 |  * xmlXPathNextAttribute: | 
 | 5926 |  * @ctxt:  the XPath Parser context | 
 | 5927 |  * @cur:  the current attribute in the traversal | 
 | 5928 |  * | 
 | 5929 |  * Traversal function for the "attribute" direction | 
 | 5930 |  * TODO: support DTD inherited default attributes | 
 | 5931 |  * | 
 | 5932 |  * Returns the next element following that axis | 
 | 5933 |  */ | 
 | 5934 | xmlNodePtr | 
 | 5935 | xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
| Daniel Veillard | e470df7 | 2001-04-18 21:41:07 +0000 | [diff] [blame] | 5936 |     if (ctxt->context->node == NULL) | 
 | 5937 | 	return(NULL); | 
 | 5938 |     if (ctxt->context->node->type != XML_ELEMENT_NODE) | 
 | 5939 | 	return(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5940 |     if (cur == NULL) { | 
 | 5941 |         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) | 
 | 5942 | 	    return(NULL); | 
 | 5943 |         return((xmlNodePtr)ctxt->context->node->properties); | 
 | 5944 |     } | 
 | 5945 |     return((xmlNodePtr)cur->next); | 
 | 5946 | } | 
 | 5947 |  | 
 | 5948 | /************************************************************************ | 
 | 5949 |  *									* | 
 | 5950 |  *		NodeTest Functions					* | 
 | 5951 |  *									* | 
 | 5952 |  ************************************************************************/ | 
 | 5953 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5954 | #define IS_FUNCTION			200 | 
 | 5955 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 5956 |  | 
 | 5957 | /************************************************************************ | 
 | 5958 |  *									* | 
 | 5959 |  *		Implicit tree core function library			* | 
 | 5960 |  *									* | 
 | 5961 |  ************************************************************************/ | 
 | 5962 |  | 
 | 5963 | /** | 
 | 5964 |  * xmlXPathRoot: | 
 | 5965 |  * @ctxt:  the XPath Parser context | 
 | 5966 |  * | 
 | 5967 |  * Initialize the context to the root of the document | 
 | 5968 |  */ | 
 | 5969 | void | 
 | 5970 | xmlXPathRoot(xmlXPathParserContextPtr ctxt) { | 
 | 5971 |     ctxt->context->node = (xmlNodePtr) ctxt->context->doc; | 
 | 5972 |     valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); | 
 | 5973 | } | 
 | 5974 |  | 
 | 5975 | /************************************************************************ | 
 | 5976 |  *									* | 
 | 5977 |  *		The explicit core function library			* | 
 | 5978 |  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	* | 
 | 5979 |  *									* | 
 | 5980 |  ************************************************************************/ | 
 | 5981 |  | 
 | 5982 |  | 
 | 5983 | /** | 
 | 5984 |  * xmlXPathLastFunction: | 
 | 5985 |  * @ctxt:  the XPath Parser context | 
 | 5986 |  * @nargs:  the number of arguments | 
 | 5987 |  * | 
 | 5988 |  * Implement the last() XPath function | 
 | 5989 |  *    number last() | 
 | 5990 |  * The last function returns the number of nodes in the context node list. | 
 | 5991 |  */ | 
 | 5992 | void | 
 | 5993 | xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 5994 |     CHECK_ARITY(0); | 
 | 5995 |     if (ctxt->context->contextSize >= 0) { | 
 | 5996 | 	valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize)); | 
 | 5997 | #ifdef DEBUG_EXPR | 
 | 5998 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 5999 | 		"last() : %d\n", ctxt->context->contextSize); | 
 | 6000 | #endif | 
 | 6001 |     } else { | 
 | 6002 | 	XP_ERROR(XPATH_INVALID_CTXT_SIZE); | 
 | 6003 |     } | 
 | 6004 | } | 
 | 6005 |  | 
 | 6006 | /** | 
 | 6007 |  * xmlXPathPositionFunction: | 
 | 6008 |  * @ctxt:  the XPath Parser context | 
 | 6009 |  * @nargs:  the number of arguments | 
 | 6010 |  * | 
 | 6011 |  * Implement the position() XPath function | 
 | 6012 |  *    number position() | 
 | 6013 |  * The position function returns the position of the context node in the | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 6014 |  * context node list. The first position is 1, and so the last position | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6015 |  * will be equal to last(). | 
 | 6016 |  */ | 
 | 6017 | void | 
 | 6018 | xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6019 |     CHECK_ARITY(0); | 
 | 6020 |     if (ctxt->context->proximityPosition >= 0) { | 
 | 6021 | 	valuePush(ctxt, | 
 | 6022 | 	      xmlXPathNewFloat((double) ctxt->context->proximityPosition)); | 
 | 6023 | #ifdef DEBUG_EXPR | 
 | 6024 | 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n", | 
 | 6025 | 		ctxt->context->proximityPosition); | 
 | 6026 | #endif | 
 | 6027 |     } else { | 
 | 6028 | 	XP_ERROR(XPATH_INVALID_CTXT_POSITION); | 
 | 6029 |     } | 
 | 6030 | } | 
 | 6031 |  | 
 | 6032 | /** | 
 | 6033 |  * xmlXPathCountFunction: | 
 | 6034 |  * @ctxt:  the XPath Parser context | 
 | 6035 |  * @nargs:  the number of arguments | 
 | 6036 |  * | 
 | 6037 |  * Implement the count() XPath function | 
 | 6038 |  *    number count(node-set) | 
 | 6039 |  */ | 
 | 6040 | void | 
 | 6041 | xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6042 |     xmlXPathObjectPtr cur; | 
 | 6043 |  | 
 | 6044 |     CHECK_ARITY(1); | 
 | 6045 |     if ((ctxt->value == NULL) ||  | 
 | 6046 | 	((ctxt->value->type != XPATH_NODESET) && | 
 | 6047 | 	 (ctxt->value->type != XPATH_XSLT_TREE))) | 
 | 6048 | 	XP_ERROR(XPATH_INVALID_TYPE); | 
 | 6049 |     cur = valuePop(ctxt); | 
 | 6050 |  | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 6051 |     if ((cur == NULL) || (cur->nodesetval == NULL)) | 
 | 6052 | 	valuePush(ctxt, xmlXPathNewFloat((double) 0)); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 6053 |     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 6054 | 	valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr)); | 
| Daniel Veillard | fe70332 | 2001-08-14 12:18:09 +0000 | [diff] [blame] | 6055 |     } else { | 
 | 6056 | 	if ((cur->nodesetval->nodeNr != 1) || | 
 | 6057 | 	    (cur->nodesetval->nodeTab == NULL)) { | 
 | 6058 | 	    valuePush(ctxt, xmlXPathNewFloat((double) 0)); | 
 | 6059 | 	} else { | 
 | 6060 | 	    xmlNodePtr tmp; | 
 | 6061 | 	    int i = 0; | 
 | 6062 |  | 
 | 6063 | 	    tmp = cur->nodesetval->nodeTab[0]; | 
 | 6064 | 	    if (tmp != NULL) { | 
 | 6065 | 		tmp = tmp->children; | 
 | 6066 | 		while (tmp != NULL) { | 
 | 6067 | 		    tmp = tmp->next; | 
 | 6068 | 		    i++; | 
 | 6069 | 		} | 
 | 6070 | 	    } | 
 | 6071 | 	    valuePush(ctxt, xmlXPathNewFloat((double) i)); | 
 | 6072 | 	} | 
 | 6073 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6074 |     xmlXPathFreeObject(cur); | 
 | 6075 | } | 
 | 6076 |  | 
 | 6077 | /** | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6078 |  * xmlXPathGetElementsByIds: | 
 | 6079 |  * @doc:  the document | 
 | 6080 |  * @ids:  a whitespace separated list of IDs | 
 | 6081 |  * | 
 | 6082 |  * Selects elements by their unique ID. | 
 | 6083 |  * | 
 | 6084 |  * Returns a node-set of selected elements. | 
 | 6085 |  */ | 
 | 6086 | static xmlNodeSetPtr | 
 | 6087 | xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { | 
 | 6088 |     xmlNodeSetPtr ret; | 
 | 6089 |     const xmlChar *cur = ids; | 
 | 6090 |     xmlChar *ID; | 
 | 6091 |     xmlAttrPtr attr; | 
 | 6092 |     xmlNodePtr elem = NULL; | 
 | 6093 |  | 
| Daniel Veillard | 7a985a1 | 2003-07-06 17:57:42 +0000 | [diff] [blame] | 6094 |     if (ids == NULL) return(NULL); | 
 | 6095 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6096 |     ret = xmlXPathNodeSetCreate(NULL); | 
 | 6097 |  | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 6098 |     while (IS_BLANK_CH(*cur)) cur++; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6099 |     while (*cur != 0) { | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 6100 | 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) | 
| Daniel Veillard | e209b33 | 2003-03-26 21:40:13 +0000 | [diff] [blame] | 6101 | 	    cur++; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6102 |  | 
 | 6103 |         ID = xmlStrndup(ids, cur - ids); | 
| Daniel Veillard | e209b33 | 2003-03-26 21:40:13 +0000 | [diff] [blame] | 6104 | 	if (ID != NULL) { | 
| Daniel Veillard | 68cb4b2 | 2004-04-18 20:55:39 +0000 | [diff] [blame] | 6105 | 	    /* | 
 | 6106 | 	     * We used to check the fact that the value passed | 
 | 6107 | 	     * was an NCName, but this generated much troubles for | 
 | 6108 | 	     * me and Aleksey Sanin, people blatantly violated that | 
 | 6109 | 	     * constaint, like Visa3D spec. | 
 | 6110 | 	     * if (xmlValidateNCName(ID, 1) == 0) | 
 | 6111 | 	     */ | 
 | 6112 | 	    attr = xmlGetID(doc, ID); | 
 | 6113 | 	    if (attr != NULL) { | 
 | 6114 | 		if (attr->type == XML_ATTRIBUTE_NODE) | 
 | 6115 | 		    elem = attr->parent; | 
 | 6116 | 		else if (attr->type == XML_ELEMENT_NODE) | 
 | 6117 | 		    elem = (xmlNodePtr) attr; | 
 | 6118 | 		else | 
 | 6119 | 		    elem = NULL; | 
 | 6120 | 		if (elem != NULL) | 
 | 6121 | 		    xmlXPathNodeSetAdd(ret, elem); | 
| Daniel Veillard | e209b33 | 2003-03-26 21:40:13 +0000 | [diff] [blame] | 6122 | 	    } | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6123 | 	    xmlFree(ID); | 
| Daniel Veillard | e209b33 | 2003-03-26 21:40:13 +0000 | [diff] [blame] | 6124 | 	} | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6125 |  | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 6126 | 	while (IS_BLANK_CH(*cur)) cur++; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6127 | 	ids = cur; | 
 | 6128 |     } | 
 | 6129 |     return(ret); | 
 | 6130 | } | 
 | 6131 |  | 
 | 6132 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6133 |  * xmlXPathIdFunction: | 
 | 6134 |  * @ctxt:  the XPath Parser context | 
 | 6135 |  * @nargs:  the number of arguments | 
 | 6136 |  * | 
 | 6137 |  * Implement the id() XPath function | 
 | 6138 |  *    node-set id(object) | 
 | 6139 |  * The id function selects elements by their unique ID | 
 | 6140 |  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, | 
 | 6141 |  * then the result is the union of the result of applying id to the | 
 | 6142 |  * string value of each of the nodes in the argument node-set. When the | 
 | 6143 |  * argument to id is of any other type, the argument is converted to a | 
 | 6144 |  * string as if by a call to the string function; the string is split | 
 | 6145 |  * into a whitespace-separated list of tokens (whitespace is any sequence | 
 | 6146 |  * of characters matching the production S); the result is a node-set | 
 | 6147 |  * containing the elements in the same document as the context node that | 
 | 6148 |  * have a unique ID equal to any of the tokens in the list. | 
 | 6149 |  */ | 
 | 6150 | void | 
 | 6151 | xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6152 |     xmlChar *tokens; | 
 | 6153 |     xmlNodeSetPtr ret; | 
 | 6154 |     xmlXPathObjectPtr obj; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6155 |  | 
 | 6156 |     CHECK_ARITY(1); | 
 | 6157 |     obj = valuePop(ctxt); | 
 | 6158 |     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 6159 |     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6160 | 	xmlNodeSetPtr ns; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6161 | 	int i; | 
 | 6162 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6163 | 	ret = xmlXPathNodeSetCreate(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6164 |  | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 6165 | 	if (obj->nodesetval != NULL) { | 
 | 6166 | 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6167 | 		tokens = | 
 | 6168 | 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); | 
 | 6169 | 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); | 
 | 6170 | 		ret = xmlXPathNodeSetMerge(ret, ns); | 
 | 6171 | 		xmlXPathFreeNodeSet(ns); | 
 | 6172 | 		if (tokens != NULL) | 
 | 6173 | 		    xmlFree(tokens); | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 6174 | 	    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6175 | 	} | 
 | 6176 |  | 
 | 6177 | 	xmlXPathFreeObject(obj); | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6178 | 	valuePush(ctxt, xmlXPathWrapNodeSet(ret)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6179 | 	return; | 
 | 6180 |     } | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6181 |     obj = xmlXPathConvertString(obj); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6182 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6183 |     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); | 
 | 6184 |     valuePush(ctxt, xmlXPathWrapNodeSet(ret)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6185 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6186 |     xmlXPathFreeObject(obj); | 
 | 6187 |     return; | 
 | 6188 | } | 
 | 6189 |  | 
 | 6190 | /** | 
 | 6191 |  * xmlXPathLocalNameFunction: | 
 | 6192 |  * @ctxt:  the XPath Parser context | 
 | 6193 |  * @nargs:  the number of arguments | 
 | 6194 |  * | 
 | 6195 |  * Implement the local-name() XPath function | 
 | 6196 |  *    string local-name(node-set?) | 
 | 6197 |  * The local-name function returns a string containing the local part | 
 | 6198 |  * of the name of the node in the argument node-set that is first in | 
 | 6199 |  * document order. If the node-set is empty or the first node has no | 
 | 6200 |  * name, an empty string is returned. If the argument is omitted it | 
 | 6201 |  * defaults to the context node. | 
 | 6202 |  */ | 
 | 6203 | void | 
 | 6204 | xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6205 |     xmlXPathObjectPtr cur; | 
 | 6206 |  | 
 | 6207 |     if (nargs == 0) { | 
 | 6208 | 	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); | 
 | 6209 | 	nargs = 1; | 
 | 6210 |     } | 
 | 6211 |  | 
 | 6212 |     CHECK_ARITY(1); | 
 | 6213 |     if ((ctxt->value == NULL) ||  | 
 | 6214 | 	((ctxt->value->type != XPATH_NODESET) && | 
 | 6215 | 	 (ctxt->value->type != XPATH_XSLT_TREE))) | 
 | 6216 | 	XP_ERROR(XPATH_INVALID_TYPE); | 
 | 6217 |     cur = valuePop(ctxt); | 
 | 6218 |  | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 6219 |     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6220 | 	valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6221 |     } else { | 
 | 6222 | 	int i = 0; /* Should be first in document order !!!!! */ | 
 | 6223 | 	switch (cur->nodesetval->nodeTab[i]->type) { | 
 | 6224 | 	case XML_ELEMENT_NODE: | 
 | 6225 | 	case XML_ATTRIBUTE_NODE: | 
 | 6226 | 	case XML_PI_NODE: | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 6227 | 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ') | 
 | 6228 | 		valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6229 | 	    else | 
 | 6230 | 		valuePush(ctxt, | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6231 | 		      xmlXPathNewString(cur->nodesetval->nodeTab[i]->name)); | 
 | 6232 | 	    break; | 
 | 6233 | 	case XML_NAMESPACE_DECL: | 
 | 6234 | 	    valuePush(ctxt, xmlXPathNewString( | 
 | 6235 | 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); | 
 | 6236 | 	    break; | 
 | 6237 | 	default: | 
 | 6238 | 	    valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6239 | 	} | 
 | 6240 |     } | 
 | 6241 |     xmlXPathFreeObject(cur); | 
 | 6242 | } | 
 | 6243 |  | 
 | 6244 | /** | 
 | 6245 |  * xmlXPathNamespaceURIFunction: | 
 | 6246 |  * @ctxt:  the XPath Parser context | 
 | 6247 |  * @nargs:  the number of arguments | 
 | 6248 |  * | 
 | 6249 |  * Implement the namespace-uri() XPath function | 
 | 6250 |  *    string namespace-uri(node-set?) | 
 | 6251 |  * The namespace-uri function returns a string containing the | 
 | 6252 |  * namespace URI of the expanded name of the node in the argument | 
 | 6253 |  * node-set that is first in document order. If the node-set is empty, | 
 | 6254 |  * the first node has no name, or the expanded name has no namespace | 
 | 6255 |  * URI, an empty string is returned. If the argument is omitted it | 
 | 6256 |  * defaults to the context node. | 
 | 6257 |  */ | 
 | 6258 | void | 
 | 6259 | xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6260 |     xmlXPathObjectPtr cur; | 
 | 6261 |  | 
 | 6262 |     if (nargs == 0) { | 
 | 6263 |         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); | 
 | 6264 | 	nargs = 1; | 
 | 6265 |     } | 
 | 6266 |     CHECK_ARITY(1); | 
 | 6267 |     if ((ctxt->value == NULL) ||  | 
 | 6268 | 	((ctxt->value->type != XPATH_NODESET) && | 
 | 6269 | 	 (ctxt->value->type != XPATH_XSLT_TREE))) | 
 | 6270 | 	XP_ERROR(XPATH_INVALID_TYPE); | 
 | 6271 |     cur = valuePop(ctxt); | 
 | 6272 |  | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 6273 |     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6274 | 	valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6275 |     } else { | 
 | 6276 | 	int i = 0; /* Should be first in document order !!!!! */ | 
 | 6277 | 	switch (cur->nodesetval->nodeTab[i]->type) { | 
 | 6278 | 	case XML_ELEMENT_NODE: | 
 | 6279 | 	case XML_ATTRIBUTE_NODE: | 
 | 6280 | 	    if (cur->nodesetval->nodeTab[i]->ns == NULL) | 
 | 6281 | 		valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6282 | 	    else | 
 | 6283 | 		valuePush(ctxt, xmlXPathNewString( | 
 | 6284 | 			  cur->nodesetval->nodeTab[i]->ns->href)); | 
 | 6285 | 	    break; | 
 | 6286 | 	default: | 
 | 6287 | 	    valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6288 | 	} | 
 | 6289 |     } | 
 | 6290 |     xmlXPathFreeObject(cur); | 
 | 6291 | } | 
 | 6292 |  | 
 | 6293 | /** | 
 | 6294 |  * xmlXPathNameFunction: | 
 | 6295 |  * @ctxt:  the XPath Parser context | 
 | 6296 |  * @nargs:  the number of arguments | 
 | 6297 |  * | 
 | 6298 |  * Implement the name() XPath function | 
 | 6299 |  *    string name(node-set?) | 
 | 6300 |  * The name function returns a string containing a QName representing | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 6301 |  * the name of the node in the argument node-set that is first in document | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6302 |  * order. The QName must represent the name with respect to the namespace | 
 | 6303 |  * declarations in effect on the node whose name is being represented. | 
 | 6304 |  * Typically, this will be the form in which the name occurred in the XML | 
 | 6305 |  * source. This need not be the case if there are namespace declarations | 
 | 6306 |  * in effect on the node that associate multiple prefixes with the same | 
 | 6307 |  * namespace. However, an implementation may include information about | 
 | 6308 |  * the original prefix in its representation of nodes; in this case, an | 
 | 6309 |  * implementation can ensure that the returned string is always the same | 
 | 6310 |  * as the QName used in the XML source. If the argument it omitted it | 
 | 6311 |  * defaults to the context node. | 
 | 6312 |  * Libxml keep the original prefix so the "real qualified name" used is | 
 | 6313 |  * returned. | 
 | 6314 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 6315 | static void | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6316 | xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) | 
 | 6317 | { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6318 |     xmlXPathObjectPtr cur; | 
 | 6319 |  | 
 | 6320 |     if (nargs == 0) { | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6321 |         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); | 
 | 6322 |         nargs = 1; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6323 |     } | 
 | 6324 |  | 
 | 6325 |     CHECK_ARITY(1); | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6326 |     if ((ctxt->value == NULL) || | 
 | 6327 |         ((ctxt->value->type != XPATH_NODESET) && | 
 | 6328 |          (ctxt->value->type != XPATH_XSLT_TREE))) | 
 | 6329 |         XP_ERROR(XPATH_INVALID_TYPE); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6330 |     cur = valuePop(ctxt); | 
 | 6331 |  | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 6332 |     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6333 |         valuePush(ctxt, xmlXPathNewCString("")); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6334 |     } else { | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6335 |         int i = 0;              /* Should be first in document order !!!!! */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6336 |  | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6337 |         switch (cur->nodesetval->nodeTab[i]->type) { | 
 | 6338 |             case XML_ELEMENT_NODE: | 
 | 6339 |             case XML_ATTRIBUTE_NODE: | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 6340 | 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ') | 
 | 6341 | 		    valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6342 | 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || | 
 | 6343 |                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6344 |                     valuePush(ctxt, | 
| Daniel Veillard | c00cda8 | 2003-04-07 10:22:39 +0000 | [diff] [blame] | 6345 | 		        xmlXPathNewString(cur->nodesetval->nodeTab[i]->name)); | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6346 |  | 
| Daniel Veillard | 652d8a9 | 2003-02-04 19:28:49 +0000 | [diff] [blame] | 6347 | 		} else { | 
| Daniel Veillard | c00cda8 | 2003-04-07 10:22:39 +0000 | [diff] [blame] | 6348 | 		    xmlChar *fullname; | 
 | 6349 | 		     | 
 | 6350 | 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, | 
 | 6351 | 				     cur->nodesetval->nodeTab[i]->ns->prefix, | 
 | 6352 | 				     NULL, 0); | 
 | 6353 | 		    if (fullname == cur->nodesetval->nodeTab[i]->name) | 
 | 6354 | 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); | 
 | 6355 | 		    if (fullname == NULL) { | 
 | 6356 | 			XP_ERROR(XPATH_MEMORY_ERROR); | 
 | 6357 | 		    } | 
 | 6358 |                     valuePush(ctxt, xmlXPathWrapString(fullname)); | 
| Daniel Veillard | 0438375 | 2001-07-08 14:27:15 +0000 | [diff] [blame] | 6359 |                 } | 
 | 6360 |                 break; | 
 | 6361 |             default: | 
 | 6362 |                 valuePush(ctxt, | 
 | 6363 |                           xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i])); | 
 | 6364 |                 xmlXPathLocalNameFunction(ctxt, 1); | 
 | 6365 |         } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6366 |     } | 
 | 6367 |     xmlXPathFreeObject(cur); | 
 | 6368 | } | 
 | 6369 |  | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 6370 |  | 
 | 6371 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6372 |  * xmlXPathStringFunction: | 
 | 6373 |  * @ctxt:  the XPath Parser context | 
 | 6374 |  * @nargs:  the number of arguments | 
 | 6375 |  * | 
 | 6376 |  * Implement the string() XPath function | 
 | 6377 |  *    string string(object?) | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 6378 |  * The string function converts an object to a string as follows: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6379 |  *    - A node-set is converted to a string by returning the value of | 
 | 6380 |  *      the node in the node-set that is first in document order. | 
 | 6381 |  *      If the node-set is empty, an empty string is returned. | 
 | 6382 |  *    - A number is converted to a string as follows | 
 | 6383 |  *      + NaN is converted to the string NaN  | 
 | 6384 |  *      + positive zero is converted to the string 0  | 
 | 6385 |  *      + negative zero is converted to the string 0  | 
 | 6386 |  *      + positive infinity is converted to the string Infinity  | 
 | 6387 |  *      + negative infinity is converted to the string -Infinity  | 
 | 6388 |  *      + if the number is an integer, the number is represented in | 
 | 6389 |  *        decimal form as a Number with no decimal point and no leading | 
 | 6390 |  *        zeros, preceded by a minus sign (-) if the number is negative | 
 | 6391 |  *      + otherwise, the number is represented in decimal form as a | 
 | 6392 |  *        Number including a decimal point with at least one digit | 
 | 6393 |  *        before the decimal point and at least one digit after the | 
 | 6394 |  *        decimal point, preceded by a minus sign (-) if the number | 
 | 6395 |  *        is negative; there must be no leading zeros before the decimal | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 6396 |  *        point apart possibly from the one required digit immediately | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6397 |  *        before the decimal point; beyond the one required digit | 
 | 6398 |  *        after the decimal point there must be as many, but only as | 
 | 6399 |  *        many, more digits as are needed to uniquely distinguish the | 
 | 6400 |  *        number from all other IEEE 754 numeric values. | 
 | 6401 |  *    - The boolean false value is converted to the string false. | 
 | 6402 |  *      The boolean true value is converted to the string true. | 
 | 6403 |  * | 
 | 6404 |  * If the argument is omitted, it defaults to a node-set with the | 
 | 6405 |  * context node as its only member. | 
 | 6406 |  */ | 
 | 6407 | void | 
 | 6408 | xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6409 |     xmlXPathObjectPtr cur; | 
 | 6410 |  | 
 | 6411 |     if (nargs == 0) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6412 | 	valuePush(ctxt, | 
 | 6413 | 		  xmlXPathWrapString( | 
 | 6414 | 			xmlXPathCastNodeToString(ctxt->context->node))); | 
 | 6415 | 	return; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6416 |     } | 
 | 6417 |  | 
 | 6418 |     CHECK_ARITY(1); | 
 | 6419 |     cur = valuePop(ctxt); | 
 | 6420 |     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 6421 |     cur = xmlXPathConvertString(cur); | 
 | 6422 |     valuePush(ctxt, cur); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6423 | } | 
 | 6424 |  | 
 | 6425 | /** | 
 | 6426 |  * xmlXPathStringLengthFunction: | 
 | 6427 |  * @ctxt:  the XPath Parser context | 
 | 6428 |  * @nargs:  the number of arguments | 
 | 6429 |  * | 
 | 6430 |  * Implement the string-length() XPath function | 
 | 6431 |  *    number string-length(string?) | 
 | 6432 |  * The string-length returns the number of characters in the string | 
 | 6433 |  * (see [3.6 Strings]). If the argument is omitted, it defaults to | 
 | 6434 |  * the context node converted to a string, in other words the value | 
 | 6435 |  * of the context node. | 
 | 6436 |  */ | 
 | 6437 | void | 
 | 6438 | xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6439 |     xmlXPathObjectPtr cur; | 
 | 6440 |  | 
 | 6441 |     if (nargs == 0) { | 
 | 6442 | 	if (ctxt->context->node == NULL) { | 
 | 6443 | 	    valuePush(ctxt, xmlXPathNewFloat(0)); | 
 | 6444 | 	} else { | 
 | 6445 | 	    xmlChar *content; | 
 | 6446 |  | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6447 | 	    content = xmlXPathCastNodeToString(ctxt->context->node); | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6448 | 	    valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content))); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6449 | 	    xmlFree(content); | 
 | 6450 | 	} | 
 | 6451 | 	return; | 
 | 6452 |     } | 
 | 6453 |     CHECK_ARITY(1); | 
 | 6454 |     CAST_TO_STRING; | 
 | 6455 |     CHECK_TYPE(XPATH_STRING); | 
 | 6456 |     cur = valuePop(ctxt); | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6457 |     valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval))); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6458 |     xmlXPathFreeObject(cur); | 
 | 6459 | } | 
 | 6460 |  | 
 | 6461 | /** | 
 | 6462 |  * xmlXPathConcatFunction: | 
 | 6463 |  * @ctxt:  the XPath Parser context | 
 | 6464 |  * @nargs:  the number of arguments | 
 | 6465 |  * | 
 | 6466 |  * Implement the concat() XPath function | 
 | 6467 |  *    string concat(string, string, string*) | 
 | 6468 |  * The concat function returns the concatenation of its arguments. | 
 | 6469 |  */ | 
 | 6470 | void | 
 | 6471 | xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6472 |     xmlXPathObjectPtr cur, newobj; | 
 | 6473 |     xmlChar *tmp; | 
 | 6474 |  | 
 | 6475 |     if (nargs < 2) { | 
 | 6476 | 	CHECK_ARITY(2); | 
 | 6477 |     } | 
 | 6478 |  | 
 | 6479 |     CAST_TO_STRING; | 
 | 6480 |     cur = valuePop(ctxt); | 
 | 6481 |     if ((cur == NULL) || (cur->type != XPATH_STRING)) { | 
 | 6482 |         xmlXPathFreeObject(cur); | 
 | 6483 | 	return; | 
 | 6484 |     } | 
 | 6485 |     nargs--; | 
 | 6486 |  | 
 | 6487 |     while (nargs > 0) { | 
 | 6488 | 	CAST_TO_STRING; | 
 | 6489 | 	newobj = valuePop(ctxt); | 
 | 6490 | 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { | 
 | 6491 | 	    xmlXPathFreeObject(newobj); | 
 | 6492 | 	    xmlXPathFreeObject(cur); | 
 | 6493 | 	    XP_ERROR(XPATH_INVALID_TYPE); | 
 | 6494 | 	} | 
 | 6495 | 	tmp = xmlStrcat(newobj->stringval, cur->stringval); | 
 | 6496 | 	newobj->stringval = cur->stringval; | 
 | 6497 | 	cur->stringval = tmp; | 
 | 6498 |  | 
 | 6499 | 	xmlXPathFreeObject(newobj); | 
 | 6500 | 	nargs--; | 
 | 6501 |     } | 
 | 6502 |     valuePush(ctxt, cur); | 
 | 6503 | } | 
 | 6504 |  | 
 | 6505 | /** | 
 | 6506 |  * xmlXPathContainsFunction: | 
 | 6507 |  * @ctxt:  the XPath Parser context | 
 | 6508 |  * @nargs:  the number of arguments | 
 | 6509 |  * | 
 | 6510 |  * Implement the contains() XPath function | 
 | 6511 |  *    boolean contains(string, string) | 
 | 6512 |  * The contains function returns true if the first argument string | 
 | 6513 |  * contains the second argument string, and otherwise returns false. | 
 | 6514 |  */ | 
 | 6515 | void | 
 | 6516 | xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6517 |     xmlXPathObjectPtr hay, needle; | 
 | 6518 |  | 
 | 6519 |     CHECK_ARITY(2); | 
 | 6520 |     CAST_TO_STRING; | 
 | 6521 |     CHECK_TYPE(XPATH_STRING); | 
 | 6522 |     needle = valuePop(ctxt); | 
 | 6523 |     CAST_TO_STRING; | 
 | 6524 |     hay = valuePop(ctxt); | 
 | 6525 |     if ((hay == NULL) || (hay->type != XPATH_STRING)) { | 
 | 6526 |         xmlXPathFreeObject(hay); | 
 | 6527 |         xmlXPathFreeObject(needle); | 
 | 6528 | 	XP_ERROR(XPATH_INVALID_TYPE); | 
 | 6529 |     } | 
 | 6530 |     if (xmlStrstr(hay->stringval, needle->stringval)) | 
 | 6531 |         valuePush(ctxt, xmlXPathNewBoolean(1)); | 
 | 6532 |     else | 
 | 6533 |         valuePush(ctxt, xmlXPathNewBoolean(0)); | 
 | 6534 |     xmlXPathFreeObject(hay); | 
 | 6535 |     xmlXPathFreeObject(needle); | 
 | 6536 | } | 
 | 6537 |  | 
 | 6538 | /** | 
 | 6539 |  * xmlXPathStartsWithFunction: | 
 | 6540 |  * @ctxt:  the XPath Parser context | 
 | 6541 |  * @nargs:  the number of arguments | 
 | 6542 |  * | 
 | 6543 |  * Implement the starts-with() XPath function | 
 | 6544 |  *    boolean starts-with(string, string) | 
 | 6545 |  * The starts-with function returns true if the first argument string | 
 | 6546 |  * starts with the second argument string, and otherwise returns false. | 
 | 6547 |  */ | 
 | 6548 | void | 
 | 6549 | xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6550 |     xmlXPathObjectPtr hay, needle; | 
 | 6551 |     int n; | 
 | 6552 |  | 
 | 6553 |     CHECK_ARITY(2); | 
 | 6554 |     CAST_TO_STRING; | 
 | 6555 |     CHECK_TYPE(XPATH_STRING); | 
 | 6556 |     needle = valuePop(ctxt); | 
 | 6557 |     CAST_TO_STRING; | 
 | 6558 |     hay = valuePop(ctxt); | 
 | 6559 |     if ((hay == NULL) || (hay->type != XPATH_STRING)) { | 
 | 6560 |         xmlXPathFreeObject(hay); | 
 | 6561 |         xmlXPathFreeObject(needle); | 
 | 6562 | 	XP_ERROR(XPATH_INVALID_TYPE); | 
 | 6563 |     } | 
 | 6564 |     n = xmlStrlen(needle->stringval); | 
 | 6565 |     if (xmlStrncmp(hay->stringval, needle->stringval, n)) | 
 | 6566 |         valuePush(ctxt, xmlXPathNewBoolean(0)); | 
 | 6567 |     else | 
 | 6568 |         valuePush(ctxt, xmlXPathNewBoolean(1)); | 
 | 6569 |     xmlXPathFreeObject(hay); | 
 | 6570 |     xmlXPathFreeObject(needle); | 
 | 6571 | } | 
 | 6572 |  | 
 | 6573 | /** | 
 | 6574 |  * xmlXPathSubstringFunction: | 
 | 6575 |  * @ctxt:  the XPath Parser context | 
 | 6576 |  * @nargs:  the number of arguments | 
 | 6577 |  * | 
 | 6578 |  * Implement the substring() XPath function | 
 | 6579 |  *    string substring(string, number, number?) | 
 | 6580 |  * The substring function returns the substring of the first argument | 
 | 6581 |  * starting at the position specified in the second argument with | 
 | 6582 |  * length specified in the third argument. For example, | 
 | 6583 |  * substring("12345",2,3) returns "234". If the third argument is not | 
 | 6584 |  * specified, it returns the substring starting at the position specified | 
 | 6585 |  * in the second argument and continuing to the end of the string. For | 
 | 6586 |  * example, substring("12345",2) returns "2345".  More precisely, each | 
 | 6587 |  * character in the string (see [3.6 Strings]) is considered to have a | 
 | 6588 |  * numeric position: the position of the first character is 1, the position | 
 | 6589 |  * of the second character is 2 and so on. The returned substring contains | 
 | 6590 |  * those characters for which the position of the character is greater than | 
 | 6591 |  * or equal to the second argument and, if the third argument is specified, | 
 | 6592 |  * less than the sum of the second and third arguments; the comparisons | 
 | 6593 |  * and addition used for the above follow the standard IEEE 754 rules. Thus: | 
 | 6594 |  *  - substring("12345", 1.5, 2.6) returns "234"  | 
 | 6595 |  *  - substring("12345", 0, 3) returns "12"  | 
 | 6596 |  *  - substring("12345", 0 div 0, 3) returns ""  | 
 | 6597 |  *  - substring("12345", 1, 0 div 0) returns ""  | 
 | 6598 |  *  - substring("12345", -42, 1 div 0) returns "12345"  | 
 | 6599 |  *  - substring("12345", -1 div 0, 1 div 0) returns ""  | 
 | 6600 |  */ | 
 | 6601 | void | 
 | 6602 | xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6603 |     xmlXPathObjectPtr str, start, len; | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6604 |     double le=0, in; | 
 | 6605 |     int i, l, m; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6606 |     xmlChar *ret; | 
 | 6607 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6608 |     if (nargs < 2) { | 
 | 6609 | 	CHECK_ARITY(2); | 
 | 6610 |     } | 
 | 6611 |     if (nargs > 3) { | 
 | 6612 | 	CHECK_ARITY(3); | 
 | 6613 |     } | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6614 |     /* | 
 | 6615 |      * take care of possible last (position) argument | 
 | 6616 |     */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6617 |     if (nargs == 3) { | 
 | 6618 | 	CAST_TO_NUMBER; | 
 | 6619 | 	CHECK_TYPE(XPATH_NUMBER); | 
 | 6620 | 	len = valuePop(ctxt); | 
 | 6621 | 	le = len->floatval; | 
 | 6622 |         xmlXPathFreeObject(len); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6623 |     } | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6624 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6625 |     CAST_TO_NUMBER; | 
 | 6626 |     CHECK_TYPE(XPATH_NUMBER); | 
 | 6627 |     start = valuePop(ctxt); | 
 | 6628 |     in = start->floatval; | 
 | 6629 |     xmlXPathFreeObject(start); | 
 | 6630 |     CAST_TO_STRING; | 
 | 6631 |     CHECK_TYPE(XPATH_STRING); | 
 | 6632 |     str = valuePop(ctxt); | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6633 |     m = xmlUTF8Strlen((const unsigned char *)str->stringval); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6634 |  | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6635 |     /* | 
 | 6636 |      * If last pos not present, calculate last position | 
 | 6637 |     */ | 
| Daniel Veillard | 9e41230 | 2002-06-10 15:59:44 +0000 | [diff] [blame] | 6638 |     if (nargs != 3) { | 
 | 6639 | 	le = (double)m; | 
 | 6640 | 	if (in < 1.0)  | 
 | 6641 | 	    in = 1.0; | 
 | 6642 |     } | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6643 |  | 
| Daniel Veillard | 0eafdef | 2002-04-10 16:14:34 +0000 | [diff] [blame] | 6644 |     /* Need to check for the special cases where either  | 
 | 6645 |      * the index is NaN, the length is NaN, or both | 
 | 6646 |      * arguments are infinity (relying on Inf + -Inf = NaN) | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6647 |      */ | 
| Daniel Veillard | 9e41230 | 2002-06-10 15:59:44 +0000 | [diff] [blame] | 6648 |     if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) { | 
| Daniel Veillard | 0eafdef | 2002-04-10 16:14:34 +0000 | [diff] [blame] | 6649 |         /* | 
| Daniel Veillard | 9e41230 | 2002-06-10 15:59:44 +0000 | [diff] [blame] | 6650 |          * To meet the requirements of the spec, the arguments | 
 | 6651 | 	 * must be converted to integer format before  | 
 | 6652 | 	 * initial index calculations are done | 
| Daniel Veillard | 0eafdef | 2002-04-10 16:14:34 +0000 | [diff] [blame] | 6653 |          * | 
| Daniel Veillard | 9e41230 | 2002-06-10 15:59:44 +0000 | [diff] [blame] | 6654 |          * First we go to integer form, rounding up | 
 | 6655 | 	 * and checking for special cases | 
| Daniel Veillard | 0eafdef | 2002-04-10 16:14:34 +0000 | [diff] [blame] | 6656 |          */ | 
 | 6657 |         i = (int) in; | 
| Daniel Veillard | 9e41230 | 2002-06-10 15:59:44 +0000 | [diff] [blame] | 6658 |         if (((double)i)+0.5 <= in) i++; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6659 |  | 
| Daniel Veillard | 9e41230 | 2002-06-10 15:59:44 +0000 | [diff] [blame] | 6660 | 	if (xmlXPathIsInf(le) == 1) { | 
 | 6661 | 	    l = m; | 
 | 6662 | 	    if (i < 1) | 
 | 6663 | 		i = 1; | 
 | 6664 | 	} | 
 | 6665 | 	else if (xmlXPathIsInf(le) == -1 || le < 0.0) | 
 | 6666 | 	    l = 0; | 
 | 6667 | 	else { | 
 | 6668 | 	    l = (int) le; | 
 | 6669 | 	    if (((double)l)+0.5 <= le) l++; | 
 | 6670 | 	} | 
 | 6671 |  | 
 | 6672 | 	/* Now we normalize inidices */ | 
 | 6673 |         i -= 1; | 
 | 6674 |         l += i; | 
 | 6675 |         if (i < 0) | 
 | 6676 |             i = 0; | 
 | 6677 |         if (l > m) | 
 | 6678 |             l = m; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6679 |  | 
| Daniel Veillard | 0eafdef | 2002-04-10 16:14:34 +0000 | [diff] [blame] | 6680 |         /* number of chars to copy */ | 
 | 6681 |         l -= i; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6682 |  | 
| Daniel Veillard | 0eafdef | 2002-04-10 16:14:34 +0000 | [diff] [blame] | 6683 |         ret = xmlUTF8Strsub(str->stringval, i, l); | 
 | 6684 |     } | 
 | 6685 |     else { | 
 | 6686 |         ret = NULL; | 
 | 6687 |     } | 
 | 6688 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6689 |     if (ret == NULL) | 
 | 6690 | 	valuePush(ctxt, xmlXPathNewCString("")); | 
 | 6691 |     else { | 
 | 6692 | 	valuePush(ctxt, xmlXPathNewString(ret)); | 
 | 6693 | 	xmlFree(ret); | 
 | 6694 |     } | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6695 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6696 |     xmlXPathFreeObject(str); | 
 | 6697 | } | 
 | 6698 |  | 
 | 6699 | /** | 
 | 6700 |  * xmlXPathSubstringBeforeFunction: | 
 | 6701 |  * @ctxt:  the XPath Parser context | 
 | 6702 |  * @nargs:  the number of arguments | 
 | 6703 |  * | 
 | 6704 |  * Implement the substring-before() XPath function | 
 | 6705 |  *    string substring-before(string, string) | 
 | 6706 |  * The substring-before function returns the substring of the first | 
 | 6707 |  * argument string that precedes the first occurrence of the second | 
 | 6708 |  * argument string in the first argument string, or the empty string | 
 | 6709 |  * if the first argument string does not contain the second argument | 
 | 6710 |  * string. For example, substring-before("1999/04/01","/") returns 1999. | 
 | 6711 |  */ | 
 | 6712 | void | 
 | 6713 | xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6714 |   xmlXPathObjectPtr str; | 
 | 6715 |   xmlXPathObjectPtr find; | 
 | 6716 |   xmlBufferPtr target; | 
 | 6717 |   const xmlChar *point; | 
 | 6718 |   int offset; | 
 | 6719 |    | 
 | 6720 |   CHECK_ARITY(2); | 
 | 6721 |   CAST_TO_STRING; | 
 | 6722 |   find = valuePop(ctxt); | 
 | 6723 |   CAST_TO_STRING; | 
 | 6724 |   str = valuePop(ctxt); | 
 | 6725 |    | 
 | 6726 |   target = xmlBufferCreate(); | 
 | 6727 |   if (target) { | 
 | 6728 |     point = xmlStrstr(str->stringval, find->stringval); | 
 | 6729 |     if (point) { | 
 | 6730 |       offset = (int)(point - str->stringval); | 
 | 6731 |       xmlBufferAdd(target, str->stringval, offset); | 
 | 6732 |     } | 
 | 6733 |     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); | 
 | 6734 |     xmlBufferFree(target); | 
 | 6735 |   } | 
 | 6736 |    | 
 | 6737 |   xmlXPathFreeObject(str); | 
 | 6738 |   xmlXPathFreeObject(find); | 
 | 6739 | } | 
 | 6740 |  | 
 | 6741 | /** | 
 | 6742 |  * xmlXPathSubstringAfterFunction: | 
 | 6743 |  * @ctxt:  the XPath Parser context | 
 | 6744 |  * @nargs:  the number of arguments | 
 | 6745 |  * | 
 | 6746 |  * Implement the substring-after() XPath function | 
 | 6747 |  *    string substring-after(string, string) | 
 | 6748 |  * The substring-after function returns the substring of the first | 
 | 6749 |  * argument string that follows the first occurrence of the second | 
 | 6750 |  * argument string in the first argument string, or the empty stringi | 
 | 6751 |  * if the first argument string does not contain the second argument | 
 | 6752 |  * string. For example, substring-after("1999/04/01","/") returns 04/01, | 
 | 6753 |  * and substring-after("1999/04/01","19") returns 99/04/01. | 
 | 6754 |  */ | 
 | 6755 | void | 
 | 6756 | xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6757 |   xmlXPathObjectPtr str; | 
 | 6758 |   xmlXPathObjectPtr find; | 
 | 6759 |   xmlBufferPtr target; | 
 | 6760 |   const xmlChar *point; | 
 | 6761 |   int offset; | 
 | 6762 |    | 
 | 6763 |   CHECK_ARITY(2); | 
 | 6764 |   CAST_TO_STRING; | 
 | 6765 |   find = valuePop(ctxt); | 
 | 6766 |   CAST_TO_STRING; | 
 | 6767 |   str = valuePop(ctxt); | 
 | 6768 |    | 
 | 6769 |   target = xmlBufferCreate(); | 
 | 6770 |   if (target) { | 
 | 6771 |     point = xmlStrstr(str->stringval, find->stringval); | 
 | 6772 |     if (point) { | 
 | 6773 |       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); | 
 | 6774 |       xmlBufferAdd(target, &str->stringval[offset], | 
 | 6775 | 		   xmlStrlen(str->stringval) - offset); | 
 | 6776 |     } | 
 | 6777 |     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); | 
 | 6778 |     xmlBufferFree(target); | 
 | 6779 |   } | 
 | 6780 |    | 
 | 6781 |   xmlXPathFreeObject(str); | 
 | 6782 |   xmlXPathFreeObject(find); | 
 | 6783 | } | 
 | 6784 |  | 
 | 6785 | /** | 
 | 6786 |  * xmlXPathNormalizeFunction: | 
 | 6787 |  * @ctxt:  the XPath Parser context | 
 | 6788 |  * @nargs:  the number of arguments | 
 | 6789 |  * | 
 | 6790 |  * Implement the normalize-space() XPath function | 
 | 6791 |  *    string normalize-space(string?) | 
 | 6792 |  * The normalize-space function returns the argument string with white | 
 | 6793 |  * space normalized by stripping leading and trailing whitespace | 
 | 6794 |  * and replacing sequences of whitespace characters by a single | 
 | 6795 |  * space. Whitespace characters are the same allowed by the S production | 
 | 6796 |  * in XML. If the argument is omitted, it defaults to the context | 
 | 6797 |  * node converted to a string, in other words the value of the context node. | 
 | 6798 |  */ | 
 | 6799 | void | 
 | 6800 | xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6801 |   xmlXPathObjectPtr obj = NULL; | 
 | 6802 |   xmlChar *source = NULL; | 
 | 6803 |   xmlBufferPtr target; | 
 | 6804 |   xmlChar blank; | 
 | 6805 |    | 
 | 6806 |   if (nargs == 0) { | 
 | 6807 |     /* Use current context node */ | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 6808 |     valuePush(ctxt, | 
 | 6809 | 	      xmlXPathWrapString( | 
 | 6810 | 		  xmlXPathCastNodeToString(ctxt->context->node))); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6811 |     nargs = 1; | 
 | 6812 |   } | 
 | 6813 |  | 
 | 6814 |   CHECK_ARITY(1); | 
 | 6815 |   CAST_TO_STRING; | 
 | 6816 |   CHECK_TYPE(XPATH_STRING); | 
 | 6817 |   obj = valuePop(ctxt); | 
 | 6818 |   source = obj->stringval; | 
 | 6819 |  | 
 | 6820 |   target = xmlBufferCreate(); | 
 | 6821 |   if (target && source) { | 
 | 6822 |      | 
 | 6823 |     /* Skip leading whitespaces */ | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 6824 |     while (IS_BLANK_CH(*source)) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6825 |       source++; | 
 | 6826 |    | 
 | 6827 |     /* Collapse intermediate whitespaces, and skip trailing whitespaces */ | 
 | 6828 |     blank = 0; | 
 | 6829 |     while (*source) { | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 6830 |       if (IS_BLANK_CH(*source)) { | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6831 | 	blank = 0x20; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6832 |       } else { | 
 | 6833 | 	if (blank) { | 
 | 6834 | 	  xmlBufferAdd(target, &blank, 1); | 
 | 6835 | 	  blank = 0; | 
 | 6836 | 	} | 
 | 6837 | 	xmlBufferAdd(target, source, 1); | 
 | 6838 |       } | 
 | 6839 |       source++; | 
 | 6840 |     } | 
 | 6841 |    | 
 | 6842 |     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); | 
 | 6843 |     xmlBufferFree(target); | 
 | 6844 |   } | 
 | 6845 |   xmlXPathFreeObject(obj); | 
 | 6846 | } | 
 | 6847 |  | 
 | 6848 | /** | 
 | 6849 |  * xmlXPathTranslateFunction: | 
 | 6850 |  * @ctxt:  the XPath Parser context | 
 | 6851 |  * @nargs:  the number of arguments | 
 | 6852 |  * | 
 | 6853 |  * Implement the translate() XPath function | 
 | 6854 |  *    string translate(string, string, string) | 
 | 6855 |  * The translate function returns the first argument string with | 
 | 6856 |  * occurrences of characters in the second argument string replaced | 
 | 6857 |  * by the character at the corresponding position in the third argument | 
 | 6858 |  * string. For example, translate("bar","abc","ABC") returns the string | 
 | 6859 |  * BAr. If there is a character in the second argument string with no | 
 | 6860 |  * character at a corresponding position in the third argument string | 
 | 6861 |  * (because the second argument string is longer than the third argument | 
 | 6862 |  * string), then occurrences of that character in the first argument | 
 | 6863 |  * string are removed. For example, translate("--aaa--","abc-","ABC") | 
 | 6864 |  * returns "AAA". If a character occurs more than once in second | 
 | 6865 |  * argument string, then the first occurrence determines the replacement | 
 | 6866 |  * character. If the third argument string is longer than the second | 
 | 6867 |  * argument string, then excess characters are ignored. | 
 | 6868 |  */ | 
 | 6869 | void | 
 | 6870 | xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6871 |     xmlXPathObjectPtr str; | 
 | 6872 |     xmlXPathObjectPtr from; | 
 | 6873 |     xmlXPathObjectPtr to; | 
 | 6874 |     xmlBufferPtr target; | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6875 |     int offset, max; | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6876 |     xmlChar ch; | 
| William M. Brack | b031cef | 2004-11-05 16:34:22 +0000 | [diff] [blame] | 6877 |     const xmlChar *point; | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6878 |     xmlChar *cptr; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6879 |  | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6880 |     CHECK_ARITY(3); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6881 |  | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6882 |     CAST_TO_STRING; | 
 | 6883 |     to = valuePop(ctxt); | 
 | 6884 |     CAST_TO_STRING; | 
 | 6885 |     from = valuePop(ctxt); | 
 | 6886 |     CAST_TO_STRING; | 
 | 6887 |     str = valuePop(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6888 |  | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6889 |     target = xmlBufferCreate(); | 
 | 6890 |     if (target) { | 
| Daniel Veillard | 97ac131 | 2001-05-30 19:14:17 +0000 | [diff] [blame] | 6891 | 	max = xmlUTF8Strlen(to->stringval); | 
 | 6892 | 	for (cptr = str->stringval; (ch=*cptr); ) { | 
 | 6893 | 	    offset = xmlUTF8Strloc(from->stringval, cptr); | 
 | 6894 | 	    if (offset >= 0) { | 
 | 6895 | 		if (offset < max) { | 
 | 6896 | 		    point = xmlUTF8Strpos(to->stringval, offset); | 
 | 6897 | 		    if (point) | 
 | 6898 | 			xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); | 
 | 6899 | 		} | 
 | 6900 | 	    } else | 
 | 6901 | 		xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); | 
 | 6902 |  | 
 | 6903 | 	    /* Step to next character in input */ | 
 | 6904 | 	    cptr++; | 
 | 6905 | 	    if ( ch & 0x80 ) { | 
 | 6906 | 		/* if not simple ascii, verify proper format */ | 
 | 6907 | 		if ( (ch & 0xc0) != 0xc0 ) { | 
 | 6908 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 6909 | 			"xmlXPathTranslateFunction: Invalid UTF8 string\n"); | 
 | 6910 | 		    break; | 
 | 6911 | 		} | 
 | 6912 | 		/* then skip over remaining bytes for this char */ | 
 | 6913 | 		while ( (ch <<= 1) & 0x80 ) | 
 | 6914 | 		    if ( (*cptr++ & 0xc0) != 0x80 ) { | 
 | 6915 | 			xmlGenericError(xmlGenericErrorContext, | 
 | 6916 | 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n"); | 
 | 6917 | 			break; | 
 | 6918 | 		    } | 
 | 6919 | 		if (ch & 0x80) /* must have had error encountered */ | 
 | 6920 | 		    break; | 
 | 6921 | 	    } | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6922 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6923 |     } | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 6924 |     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); | 
 | 6925 |     xmlBufferFree(target); | 
 | 6926 |     xmlXPathFreeObject(str); | 
 | 6927 |     xmlXPathFreeObject(from); | 
 | 6928 |     xmlXPathFreeObject(to); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6929 | } | 
 | 6930 |  | 
 | 6931 | /** | 
 | 6932 |  * xmlXPathBooleanFunction: | 
 | 6933 |  * @ctxt:  the XPath Parser context | 
 | 6934 |  * @nargs:  the number of arguments | 
 | 6935 |  * | 
 | 6936 |  * Implement the boolean() XPath function | 
 | 6937 |  *    boolean boolean(object) | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 6938 |  * The boolean function converts its argument to a boolean as follows: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6939 |  *    - a number is true if and only if it is neither positive or | 
 | 6940 |  *      negative zero nor NaN | 
 | 6941 |  *    - a node-set is true if and only if it is non-empty | 
 | 6942 |  *    - a string is true if and only if its length is non-zero | 
 | 6943 |  */ | 
 | 6944 | void | 
 | 6945 | xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6946 |     xmlXPathObjectPtr cur; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6947 |  | 
 | 6948 |     CHECK_ARITY(1); | 
 | 6949 |     cur = valuePop(ctxt); | 
 | 6950 |     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 6951 |     cur = xmlXPathConvertBoolean(cur); | 
 | 6952 |     valuePush(ctxt, cur); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 6953 | } | 
 | 6954 |  | 
 | 6955 | /** | 
 | 6956 |  * xmlXPathNotFunction: | 
 | 6957 |  * @ctxt:  the XPath Parser context | 
 | 6958 |  * @nargs:  the number of arguments | 
 | 6959 |  * | 
 | 6960 |  * Implement the not() XPath function | 
 | 6961 |  *    boolean not(boolean) | 
 | 6962 |  * The not function returns true if its argument is false, | 
 | 6963 |  * and false otherwise. | 
 | 6964 |  */ | 
 | 6965 | void | 
 | 6966 | xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6967 |     CHECK_ARITY(1); | 
 | 6968 |     CAST_TO_BOOLEAN; | 
 | 6969 |     CHECK_TYPE(XPATH_BOOLEAN); | 
 | 6970 |     ctxt->value->boolval = ! ctxt->value->boolval; | 
 | 6971 | } | 
 | 6972 |  | 
 | 6973 | /** | 
 | 6974 |  * xmlXPathTrueFunction: | 
 | 6975 |  * @ctxt:  the XPath Parser context | 
 | 6976 |  * @nargs:  the number of arguments | 
 | 6977 |  * | 
 | 6978 |  * Implement the true() XPath function | 
 | 6979 |  *    boolean true() | 
 | 6980 |  */ | 
 | 6981 | void | 
 | 6982 | xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6983 |     CHECK_ARITY(0); | 
 | 6984 |     valuePush(ctxt, xmlXPathNewBoolean(1)); | 
 | 6985 | } | 
 | 6986 |  | 
 | 6987 | /** | 
 | 6988 |  * xmlXPathFalseFunction: | 
 | 6989 |  * @ctxt:  the XPath Parser context | 
 | 6990 |  * @nargs:  the number of arguments | 
 | 6991 |  * | 
 | 6992 |  * Implement the false() XPath function | 
 | 6993 |  *    boolean false() | 
 | 6994 |  */ | 
 | 6995 | void | 
 | 6996 | xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 6997 |     CHECK_ARITY(0); | 
 | 6998 |     valuePush(ctxt, xmlXPathNewBoolean(0)); | 
 | 6999 | } | 
 | 7000 |  | 
 | 7001 | /** | 
 | 7002 |  * xmlXPathLangFunction: | 
 | 7003 |  * @ctxt:  the XPath Parser context | 
 | 7004 |  * @nargs:  the number of arguments | 
 | 7005 |  * | 
 | 7006 |  * Implement the lang() XPath function | 
 | 7007 |  *    boolean lang(string) | 
 | 7008 |  * The lang function returns true or false depending on whether the | 
 | 7009 |  * language of the context node as specified by xml:lang attributes | 
 | 7010 |  * is the same as or is a sublanguage of the language specified by | 
 | 7011 |  * the argument string. The language of the context node is determined | 
 | 7012 |  * by the value of the xml:lang attribute on the context node, or, if | 
 | 7013 |  * the context node has no xml:lang attribute, by the value of the | 
 | 7014 |  * xml:lang attribute on the nearest ancestor of the context node that | 
 | 7015 |  * has an xml:lang attribute. If there is no such attribute, then lang | 
 | 7016 |  * returns false. If there is such an attribute, then lang returns | 
 | 7017 |  * true if the attribute value is equal to the argument ignoring case, | 
 | 7018 |  * or if there is some suffix starting with - such that the attribute | 
 | 7019 |  * value is equal to the argument ignoring that suffix of the attribute | 
 | 7020 |  * value and ignoring case. | 
 | 7021 |  */ | 
 | 7022 | void | 
 | 7023 | xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 7024 |     xmlXPathObjectPtr val; | 
 | 7025 |     const xmlChar *theLang; | 
 | 7026 |     const xmlChar *lang; | 
 | 7027 |     int ret = 0; | 
 | 7028 |     int i; | 
 | 7029 |  | 
 | 7030 |     CHECK_ARITY(1); | 
 | 7031 |     CAST_TO_STRING; | 
 | 7032 |     CHECK_TYPE(XPATH_STRING); | 
 | 7033 |     val = valuePop(ctxt); | 
 | 7034 |     lang = val->stringval; | 
 | 7035 |     theLang = xmlNodeGetLang(ctxt->context->node); | 
 | 7036 |     if ((theLang != NULL) && (lang != NULL)) { | 
 | 7037 |         for (i = 0;lang[i] != 0;i++) | 
 | 7038 | 	    if (toupper(lang[i]) != toupper(theLang[i])) | 
 | 7039 | 	        goto not_equal; | 
 | 7040 |         ret = 1; | 
 | 7041 |     } | 
 | 7042 | not_equal: | 
| William M. Brack | a59ddb5 | 2004-02-25 08:12:32 +0000 | [diff] [blame] | 7043 |     xmlFree((void *)theLang); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7044 |     xmlXPathFreeObject(val); | 
 | 7045 |     valuePush(ctxt, xmlXPathNewBoolean(ret)); | 
 | 7046 | } | 
 | 7047 |  | 
 | 7048 | /** | 
 | 7049 |  * xmlXPathNumberFunction: | 
 | 7050 |  * @ctxt:  the XPath Parser context | 
 | 7051 |  * @nargs:  the number of arguments | 
 | 7052 |  * | 
 | 7053 |  * Implement the number() XPath function | 
 | 7054 |  *    number number(object?) | 
 | 7055 |  */ | 
 | 7056 | void | 
 | 7057 | xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 7058 |     xmlXPathObjectPtr cur; | 
 | 7059 |     double res; | 
 | 7060 |  | 
 | 7061 |     if (nargs == 0) { | 
 | 7062 | 	if (ctxt->context->node == NULL) { | 
 | 7063 | 	    valuePush(ctxt, xmlXPathNewFloat(0.0)); | 
 | 7064 | 	} else { | 
 | 7065 | 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node); | 
 | 7066 |  | 
 | 7067 | 	    res = xmlXPathStringEvalNumber(content); | 
 | 7068 | 	    valuePush(ctxt, xmlXPathNewFloat(res)); | 
 | 7069 | 	    xmlFree(content); | 
 | 7070 | 	} | 
 | 7071 | 	return; | 
 | 7072 |     } | 
 | 7073 |  | 
 | 7074 |     CHECK_ARITY(1); | 
 | 7075 |     cur = valuePop(ctxt); | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 7076 |     cur = xmlXPathConvertNumber(cur); | 
 | 7077 |     valuePush(ctxt, cur); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7078 | } | 
 | 7079 |  | 
 | 7080 | /** | 
 | 7081 |  * xmlXPathSumFunction: | 
 | 7082 |  * @ctxt:  the XPath Parser context | 
 | 7083 |  * @nargs:  the number of arguments | 
 | 7084 |  * | 
 | 7085 |  * Implement the sum() XPath function | 
 | 7086 |  *    number sum(node-set) | 
 | 7087 |  * The sum function returns the sum of the values of the nodes in | 
 | 7088 |  * the argument node-set. | 
 | 7089 |  */ | 
 | 7090 | void | 
 | 7091 | xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 7092 |     xmlXPathObjectPtr cur; | 
 | 7093 |     int i; | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 7094 |     double res = 0.0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7095 |  | 
 | 7096 |     CHECK_ARITY(1); | 
 | 7097 |     if ((ctxt->value == NULL) ||  | 
 | 7098 | 	((ctxt->value->type != XPATH_NODESET) && | 
 | 7099 | 	 (ctxt->value->type != XPATH_XSLT_TREE))) | 
 | 7100 | 	XP_ERROR(XPATH_INVALID_TYPE); | 
 | 7101 |     cur = valuePop(ctxt); | 
 | 7102 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 7103 |     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { | 
| Daniel Veillard | ba0b8c9 | 2001-05-15 09:43:47 +0000 | [diff] [blame] | 7104 | 	for (i = 0; i < cur->nodesetval->nodeNr; i++) { | 
 | 7105 | 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7106 | 	} | 
 | 7107 |     } | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 7108 |     valuePush(ctxt, xmlXPathNewFloat(res)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7109 |     xmlXPathFreeObject(cur); | 
 | 7110 | } | 
 | 7111 |  | 
 | 7112 | /** | 
 | 7113 |  * xmlXPathFloorFunction: | 
 | 7114 |  * @ctxt:  the XPath Parser context | 
 | 7115 |  * @nargs:  the number of arguments | 
 | 7116 |  * | 
 | 7117 |  * Implement the floor() XPath function | 
 | 7118 |  *    number floor(number) | 
 | 7119 |  * The floor function returns the largest (closest to positive infinity) | 
 | 7120 |  * number that is not greater than the argument and that is an integer. | 
 | 7121 |  */ | 
 | 7122 | void | 
 | 7123 | xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
| Daniel Veillard | 56cd18b | 2002-03-22 14:14:43 +0000 | [diff] [blame] | 7124 |     double f; | 
 | 7125 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7126 |     CHECK_ARITY(1); | 
 | 7127 |     CAST_TO_NUMBER; | 
 | 7128 |     CHECK_TYPE(XPATH_NUMBER); | 
| Daniel Veillard | 56cd18b | 2002-03-22 14:14:43 +0000 | [diff] [blame] | 7129 |  | 
 | 7130 |     f = (double)((int) ctxt->value->floatval); | 
 | 7131 |     if (f != ctxt->value->floatval) { | 
 | 7132 | 	if (ctxt->value->floatval > 0) | 
 | 7133 | 	    ctxt->value->floatval = f; | 
 | 7134 | 	else | 
 | 7135 | 	    ctxt->value->floatval = f - 1; | 
 | 7136 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7137 | } | 
 | 7138 |  | 
 | 7139 | /** | 
 | 7140 |  * xmlXPathCeilingFunction: | 
 | 7141 |  * @ctxt:  the XPath Parser context | 
 | 7142 |  * @nargs:  the number of arguments | 
 | 7143 |  * | 
 | 7144 |  * Implement the ceiling() XPath function | 
 | 7145 |  *    number ceiling(number) | 
 | 7146 |  * The ceiling function returns the smallest (closest to negative infinity) | 
 | 7147 |  * number that is not less than the argument and that is an integer. | 
 | 7148 |  */ | 
 | 7149 | void | 
 | 7150 | xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 7151 |     double f; | 
 | 7152 |  | 
 | 7153 |     CHECK_ARITY(1); | 
 | 7154 |     CAST_TO_NUMBER; | 
 | 7155 |     CHECK_TYPE(XPATH_NUMBER); | 
 | 7156 |  | 
 | 7157 | #if 0 | 
 | 7158 |     ctxt->value->floatval = ceil(ctxt->value->floatval); | 
 | 7159 | #else | 
 | 7160 |     f = (double)((int) ctxt->value->floatval); | 
| Daniel Veillard | 56cd18b | 2002-03-22 14:14:43 +0000 | [diff] [blame] | 7161 |     if (f != ctxt->value->floatval) { | 
 | 7162 | 	if (ctxt->value->floatval > 0) | 
 | 7163 | 	    ctxt->value->floatval = f + 1; | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 7164 | 	else { | 
 | 7165 | 	    if (ctxt->value->floatval < 0 && f == 0) | 
 | 7166 | 	        ctxt->value->floatval = xmlXPathNZERO; | 
 | 7167 | 	    else | 
 | 7168 | 	        ctxt->value->floatval = f; | 
 | 7169 | 	} | 
 | 7170 |  | 
| Daniel Veillard | 56cd18b | 2002-03-22 14:14:43 +0000 | [diff] [blame] | 7171 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7172 | #endif | 
 | 7173 | } | 
 | 7174 |  | 
 | 7175 | /** | 
 | 7176 |  * xmlXPathRoundFunction: | 
 | 7177 |  * @ctxt:  the XPath Parser context | 
 | 7178 |  * @nargs:  the number of arguments | 
 | 7179 |  * | 
 | 7180 |  * Implement the round() XPath function | 
 | 7181 |  *    number round(number) | 
 | 7182 |  * The round function returns the number that is closest to the | 
 | 7183 |  * argument and that is an integer. If there are two such numbers, | 
 | 7184 |  * then the one that is even is returned. | 
 | 7185 |  */ | 
 | 7186 | void | 
 | 7187 | xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 7188 |     double f; | 
 | 7189 |  | 
 | 7190 |     CHECK_ARITY(1); | 
 | 7191 |     CAST_TO_NUMBER; | 
 | 7192 |     CHECK_TYPE(XPATH_NUMBER); | 
 | 7193 |  | 
| Daniel Veillard | cda9692 | 2001-08-21 10:56:31 +0000 | [diff] [blame] | 7194 |     if ((xmlXPathIsNaN(ctxt->value->floatval)) || | 
 | 7195 | 	(xmlXPathIsInf(ctxt->value->floatval) == 1) || | 
 | 7196 | 	(xmlXPathIsInf(ctxt->value->floatval) == -1) || | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7197 | 	(ctxt->value->floatval == 0.0)) | 
 | 7198 | 	return; | 
 | 7199 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7200 |     f = (double)((int) ctxt->value->floatval); | 
| Daniel Veillard | 56cd18b | 2002-03-22 14:14:43 +0000 | [diff] [blame] | 7201 |     if (ctxt->value->floatval < 0) { | 
 | 7202 | 	if (ctxt->value->floatval < f - 0.5) | 
 | 7203 | 	    ctxt->value->floatval = f - 1; | 
 | 7204 | 	else  | 
 | 7205 | 	    ctxt->value->floatval = f; | 
| Daniel Veillard | 5fc1f08 | 2002-03-27 09:05:40 +0000 | [diff] [blame] | 7206 | 	if (ctxt->value->floatval == 0) | 
 | 7207 | 	    ctxt->value->floatval = xmlXPathNZERO; | 
| Daniel Veillard | 56cd18b | 2002-03-22 14:14:43 +0000 | [diff] [blame] | 7208 |     } else { | 
 | 7209 | 	if (ctxt->value->floatval < f + 0.5) | 
 | 7210 | 	    ctxt->value->floatval = f; | 
 | 7211 | 	else  | 
 | 7212 | 	    ctxt->value->floatval = f + 1; | 
 | 7213 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7214 | } | 
 | 7215 |  | 
 | 7216 | /************************************************************************ | 
 | 7217 |  *									* | 
 | 7218 |  *			The Parser					* | 
 | 7219 |  *									* | 
 | 7220 |  ************************************************************************/ | 
 | 7221 |  | 
 | 7222 | /* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 7223 |  * a few forward declarations since we use a recursive call based | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7224 |  * implementation. | 
 | 7225 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7226 | static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 7227 | static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7228 | static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7229 | static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7230 | static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, | 
 | 7231 | 	                                  int qualified); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7232 |  | 
 | 7233 | /** | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7234 |  * xmlXPathCurrentChar: | 
 | 7235 |  * @ctxt:  the XPath parser context | 
 | 7236 |  * @cur:  pointer to the beginning of the char | 
 | 7237 |  * @len:  pointer to the length of the char read | 
 | 7238 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 7239 |  * The current char value, if using UTF-8 this may actually span multiple | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7240 |  * bytes in the input buffer. | 
 | 7241 |  * | 
| Daniel Veillard | 60087f3 | 2001-10-10 09:45:09 +0000 | [diff] [blame] | 7242 |  * Returns the current char value and its length | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7243 |  */ | 
 | 7244 |  | 
 | 7245 | static int | 
 | 7246 | xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { | 
 | 7247 |     unsigned char c; | 
 | 7248 |     unsigned int val; | 
 | 7249 |     const xmlChar *cur; | 
 | 7250 |  | 
 | 7251 |     if (ctxt == NULL) | 
 | 7252 | 	return(0); | 
 | 7253 |     cur = ctxt->cur; | 
 | 7254 |  | 
 | 7255 |     /* | 
 | 7256 |      * We are supposed to handle UTF8, check it's valid | 
 | 7257 |      * From rfc2044: encoding of the Unicode values on UTF-8: | 
 | 7258 |      * | 
 | 7259 |      * UCS-4 range (hex.)           UTF-8 octet sequence (binary) | 
 | 7260 |      * 0000 0000-0000 007F   0xxxxxxx | 
 | 7261 |      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx | 
 | 7262 |      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx  | 
 | 7263 |      * | 
 | 7264 |      * Check for the 0x110000 limit too | 
 | 7265 |      */ | 
 | 7266 |     c = *cur; | 
 | 7267 |     if (c & 0x80) { | 
 | 7268 | 	if ((cur[1] & 0xc0) != 0x80) | 
 | 7269 | 	    goto encoding_error; | 
 | 7270 | 	if ((c & 0xe0) == 0xe0) { | 
 | 7271 |  | 
 | 7272 | 	    if ((cur[2] & 0xc0) != 0x80) | 
 | 7273 | 		goto encoding_error; | 
 | 7274 | 	    if ((c & 0xf0) == 0xf0) { | 
 | 7275 | 		if (((c & 0xf8) != 0xf0) || | 
 | 7276 | 		    ((cur[3] & 0xc0) != 0x80)) | 
 | 7277 | 		    goto encoding_error; | 
 | 7278 | 		/* 4-byte code */ | 
 | 7279 | 		*len = 4; | 
 | 7280 | 		val = (cur[0] & 0x7) << 18; | 
 | 7281 | 		val |= (cur[1] & 0x3f) << 12; | 
 | 7282 | 		val |= (cur[2] & 0x3f) << 6; | 
 | 7283 | 		val |= cur[3] & 0x3f; | 
 | 7284 | 	    } else { | 
 | 7285 | 	      /* 3-byte code */ | 
 | 7286 | 		*len = 3; | 
 | 7287 | 		val = (cur[0] & 0xf) << 12; | 
 | 7288 | 		val |= (cur[1] & 0x3f) << 6; | 
 | 7289 | 		val |= cur[2] & 0x3f; | 
 | 7290 | 	    } | 
 | 7291 | 	} else { | 
 | 7292 | 	  /* 2-byte code */ | 
 | 7293 | 	    *len = 2; | 
 | 7294 | 	    val = (cur[0] & 0x1f) << 6; | 
 | 7295 | 	    val |= cur[1] & 0x3f; | 
 | 7296 | 	} | 
 | 7297 | 	if (!IS_CHAR(val)) { | 
 | 7298 | 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR); | 
 | 7299 | 	}     | 
 | 7300 | 	return(val); | 
 | 7301 |     } else { | 
 | 7302 | 	/* 1-byte code */ | 
 | 7303 | 	*len = 1; | 
 | 7304 | 	return((int) *cur); | 
 | 7305 |     } | 
 | 7306 | encoding_error: | 
 | 7307 |     /* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 7308 |      * If we detect an UTF8 error that probably means that the | 
 | 7309 |      * input encoding didn't get properly advertised in the | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7310 |      * declaration header. Report the error and switch the encoding | 
 | 7311 |      * to ISO-Latin-1 (if you don't like this policy, just declare the | 
 | 7312 |      * encoding !) | 
 | 7313 |      */ | 
| Daniel Veillard | 42596ad | 2001-05-22 16:57:14 +0000 | [diff] [blame] | 7314 |     *len = 0; | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7315 |     XP_ERROR0(XPATH_ENCODING_ERROR); | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7316 | } | 
 | 7317 |  | 
 | 7318 | /** | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7319 |  * xmlXPathParseNCName: | 
 | 7320 |  * @ctxt:  the XPath Parser context | 
 | 7321 |  * | 
 | 7322 |  * parse an XML namespace non qualified name. | 
 | 7323 |  * | 
 | 7324 |  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* | 
 | 7325 |  * | 
 | 7326 |  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | | 
 | 7327 |  *                       CombiningChar | Extender | 
 | 7328 |  * | 
 | 7329 |  * Returns the namespace name or NULL | 
 | 7330 |  */ | 
 | 7331 |  | 
 | 7332 | xmlChar * | 
 | 7333 | xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7334 |     const xmlChar *in; | 
 | 7335 |     xmlChar *ret; | 
 | 7336 |     int count = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7337 |  | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7338 |     /* | 
 | 7339 |      * Accelerator for simple ASCII names | 
 | 7340 |      */ | 
 | 7341 |     in = ctxt->cur; | 
 | 7342 |     if (((*in >= 0x61) && (*in <= 0x7A)) || | 
 | 7343 | 	((*in >= 0x41) && (*in <= 0x5A)) || | 
 | 7344 | 	(*in == '_')) { | 
 | 7345 | 	in++; | 
 | 7346 | 	while (((*in >= 0x61) && (*in <= 0x7A)) || | 
 | 7347 | 	       ((*in >= 0x41) && (*in <= 0x5A)) || | 
 | 7348 | 	       ((*in >= 0x30) && (*in <= 0x39)) || | 
| Daniel Veillard | 9a89a8a | 2001-06-27 11:13:35 +0000 | [diff] [blame] | 7349 | 	       (*in == '_') || (*in == '.') || | 
 | 7350 | 	       (*in == '-')) | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7351 | 	    in++; | 
 | 7352 | 	if ((*in == ' ') || (*in == '>') || (*in == '/') || | 
 | 7353 |             (*in == '[') || (*in == ']') || (*in == ':') || | 
 | 7354 |             (*in == '@') || (*in == '*')) { | 
 | 7355 | 	    count = in - ctxt->cur; | 
 | 7356 | 	    if (count == 0) | 
 | 7357 | 		return(NULL); | 
 | 7358 | 	    ret = xmlStrndup(ctxt->cur, count); | 
 | 7359 | 	    ctxt->cur = in; | 
 | 7360 | 	    return(ret); | 
 | 7361 | 	} | 
 | 7362 |     } | 
 | 7363 |     return(xmlXPathParseNameComplex(ctxt, 0)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7364 | } | 
 | 7365 |  | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7366 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7367 | /** | 
 | 7368 |  * xmlXPathParseQName: | 
 | 7369 |  * @ctxt:  the XPath Parser context | 
 | 7370 |  * @prefix:  a xmlChar **  | 
 | 7371 |  * | 
 | 7372 |  * parse an XML qualified name | 
 | 7373 |  * | 
 | 7374 |  * [NS 5] QName ::= (Prefix ':')? LocalPart | 
 | 7375 |  * | 
 | 7376 |  * [NS 6] Prefix ::= NCName | 
 | 7377 |  * | 
 | 7378 |  * [NS 7] LocalPart ::= NCName | 
 | 7379 |  * | 
 | 7380 |  * Returns the function returns the local part, and prefix is updated | 
 | 7381 |  *   to get the Prefix if any. | 
 | 7382 |  */ | 
 | 7383 |  | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 7384 | static xmlChar * | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7385 | xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { | 
 | 7386 |     xmlChar *ret = NULL; | 
 | 7387 |  | 
 | 7388 |     *prefix = NULL; | 
 | 7389 |     ret = xmlXPathParseNCName(ctxt); | 
 | 7390 |     if (CUR == ':') { | 
 | 7391 |         *prefix = ret; | 
 | 7392 | 	NEXT; | 
 | 7393 | 	ret = xmlXPathParseNCName(ctxt); | 
 | 7394 |     } | 
 | 7395 |     return(ret); | 
 | 7396 | } | 
 | 7397 |  | 
 | 7398 | /** | 
 | 7399 |  * xmlXPathParseName: | 
 | 7400 |  * @ctxt:  the XPath Parser context | 
 | 7401 |  * | 
 | 7402 |  * parse an XML name | 
 | 7403 |  * | 
 | 7404 |  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | | 
 | 7405 |  *                  CombiningChar | Extender | 
 | 7406 |  * | 
 | 7407 |  * [5] Name ::= (Letter | '_' | ':') (NameChar)* | 
 | 7408 |  * | 
 | 7409 |  * Returns the namespace name or NULL | 
 | 7410 |  */ | 
 | 7411 |  | 
 | 7412 | xmlChar * | 
 | 7413 | xmlXPathParseName(xmlXPathParserContextPtr ctxt) { | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7414 |     const xmlChar *in; | 
 | 7415 |     xmlChar *ret; | 
 | 7416 |     int count = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7417 |  | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7418 |     /* | 
 | 7419 |      * Accelerator for simple ASCII names | 
 | 7420 |      */ | 
 | 7421 |     in = ctxt->cur; | 
 | 7422 |     if (((*in >= 0x61) && (*in <= 0x7A)) || | 
 | 7423 | 	((*in >= 0x41) && (*in <= 0x5A)) || | 
 | 7424 | 	(*in == '_') || (*in == ':')) { | 
 | 7425 | 	in++; | 
 | 7426 | 	while (((*in >= 0x61) && (*in <= 0x7A)) || | 
 | 7427 | 	       ((*in >= 0x41) && (*in <= 0x5A)) || | 
 | 7428 | 	       ((*in >= 0x30) && (*in <= 0x39)) || | 
| Daniel Veillard | 76d66f4 | 2001-05-16 21:05:17 +0000 | [diff] [blame] | 7429 | 	       (*in == '_') || (*in == '-') || | 
 | 7430 | 	       (*in == ':') || (*in == '.')) | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7431 | 	    in++; | 
| Daniel Veillard | 76d66f4 | 2001-05-16 21:05:17 +0000 | [diff] [blame] | 7432 | 	if ((*in > 0) && (*in < 0x80)) { | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7433 | 	    count = in - ctxt->cur; | 
 | 7434 | 	    ret = xmlStrndup(ctxt->cur, count); | 
 | 7435 | 	    ctxt->cur = in; | 
 | 7436 | 	    return(ret); | 
 | 7437 | 	} | 
 | 7438 |     } | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7439 |     return(xmlXPathParseNameComplex(ctxt, 1)); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7440 | } | 
 | 7441 |  | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7442 | static xmlChar * | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7443 | xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7444 |     xmlChar buf[XML_MAX_NAMELEN + 5]; | 
 | 7445 |     int len = 0, l; | 
 | 7446 |     int c; | 
 | 7447 |  | 
 | 7448 |     /* | 
 | 7449 |      * Handler for more complex cases | 
 | 7450 |      */ | 
 | 7451 |     c = CUR_CHAR(l); | 
 | 7452 |     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7453 |         (c == '[') || (c == ']') || (c == '@') || /* accelerators */ | 
 | 7454 |         (c == '*') || /* accelerators */ | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7455 | 	(!IS_LETTER(c) && (c != '_') && | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7456 |          ((qualified) && (c != ':')))) { | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7457 | 	return(NULL); | 
 | 7458 |     } | 
 | 7459 |  | 
 | 7460 |     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ | 
 | 7461 | 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) || | 
 | 7462 |             (c == '.') || (c == '-') || | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7463 | 	    (c == '_') || ((qualified) && (c == ':')) ||  | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7464 | 	    (IS_COMBINING(c)) || | 
 | 7465 | 	    (IS_EXTENDER(c)))) { | 
 | 7466 | 	COPY_BUF(l,buf,len,c); | 
 | 7467 | 	NEXTL(l); | 
 | 7468 | 	c = CUR_CHAR(l); | 
 | 7469 | 	if (len >= XML_MAX_NAMELEN) { | 
 | 7470 | 	    /* | 
 | 7471 | 	     * Okay someone managed to make a huge name, so he's ready to pay | 
 | 7472 | 	     * for the processing speed. | 
 | 7473 | 	     */ | 
 | 7474 | 	    xmlChar *buffer; | 
 | 7475 | 	    int max = len * 2; | 
 | 7476 | 	     | 
| Daniel Veillard | 3c908dc | 2003-04-19 00:07:51 +0000 | [diff] [blame] | 7477 | 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7478 | 	    if (buffer == NULL) { | 
 | 7479 | 		XP_ERROR0(XPATH_MEMORY_ERROR); | 
 | 7480 | 	    } | 
 | 7481 | 	    memcpy(buffer, buf, len); | 
 | 7482 | 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ | 
 | 7483 | 		   (c == '.') || (c == '-') || | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7484 | 		   (c == '_') || ((qualified) && (c == ':')) ||  | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7485 | 		   (IS_COMBINING(c)) || | 
 | 7486 | 		   (IS_EXTENDER(c))) { | 
 | 7487 | 		if (len + 10 > max) { | 
 | 7488 | 		    max *= 2; | 
 | 7489 | 		    buffer = (xmlChar *) xmlRealloc(buffer, | 
 | 7490 | 			                            max * sizeof(xmlChar)); | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7491 | 		    if (buffer == NULL) { | 
 | 7492 | 			XP_ERROR0(XPATH_MEMORY_ERROR); | 
 | 7493 | 		    } | 
 | 7494 | 		} | 
 | 7495 | 		COPY_BUF(l,buffer,len,c); | 
 | 7496 | 		NEXTL(l); | 
 | 7497 | 		c = CUR_CHAR(l); | 
 | 7498 | 	    } | 
 | 7499 | 	    buffer[len] = 0; | 
 | 7500 | 	    return(buffer); | 
 | 7501 | 	} | 
 | 7502 |     } | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 7503 |     if (len == 0) | 
 | 7504 | 	return(NULL); | 
| Daniel Veillard | 61d80a2 | 2001-04-27 17:13:01 +0000 | [diff] [blame] | 7505 |     return(xmlStrndup(buf, len)); | 
 | 7506 | } | 
| Daniel Veillard | 3cd7240 | 2002-05-13 10:33:30 +0000 | [diff] [blame] | 7507 |  | 
 | 7508 | #define MAX_FRAC 20 | 
 | 7509 |  | 
| William M. Brack | 372a445 | 2004-02-17 13:09:23 +0000 | [diff] [blame] | 7510 | /* | 
 | 7511 |  * These are used as divisors for the fractional part of a number. | 
 | 7512 |  * Since the table includes 1.0 (representing '0' fractional digits), | 
 | 7513 |  * it must be dimensioned at MAX_FRAC+1 (bug 133921) | 
 | 7514 |  */ | 
 | 7515 | static double my_pow10[MAX_FRAC+1] = { | 
| Daniel Veillard | 3cd7240 | 2002-05-13 10:33:30 +0000 | [diff] [blame] | 7516 |     1.0, 10.0, 100.0, 1000.0, 10000.0, | 
 | 7517 |     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, | 
 | 7518 |     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, | 
 | 7519 |     100000000000000.0, | 
 | 7520 |     1000000000000000.0, 10000000000000000.0, 100000000000000000.0, | 
| William M. Brack | 372a445 | 2004-02-17 13:09:23 +0000 | [diff] [blame] | 7521 |     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 | 
| Daniel Veillard | 3cd7240 | 2002-05-13 10:33:30 +0000 | [diff] [blame] | 7522 | }; | 
 | 7523 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7524 | /** | 
 | 7525 |  * xmlXPathStringEvalNumber: | 
 | 7526 |  * @str:  A string to scan | 
 | 7527 |  * | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7528 |  *  [30a]  Float  ::= Number ('e' Digits?)? | 
 | 7529 |  * | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7530 |  *  [30]   Number ::=   Digits ('.' Digits?)? | 
 | 7531 |  *                    | '.' Digits  | 
 | 7532 |  *  [31]   Digits ::=   [0-9]+ | 
 | 7533 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7534 |  * Compile a Number in the string | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7535 |  * In complement of the Number expression, this function also handles | 
 | 7536 |  * negative values : '-' Number. | 
 | 7537 |  * | 
 | 7538 |  * Returns the double value. | 
 | 7539 |  */ | 
 | 7540 | double | 
 | 7541 | xmlXPathStringEvalNumber(const xmlChar *str) { | 
 | 7542 |     const xmlChar *cur = str; | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7543 |     double ret; | 
| Daniel Veillard | b06c614 | 2001-08-27 14:26:30 +0000 | [diff] [blame] | 7544 |     int ok = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7545 |     int isneg = 0; | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7546 |     int exponent = 0; | 
 | 7547 |     int is_exponent_negative = 0; | 
| Daniel Veillard | b06c614 | 2001-08-27 14:26:30 +0000 | [diff] [blame] | 7548 | #ifdef __GNUC__ | 
 | 7549 |     unsigned long tmp = 0; | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7550 |     double temp; | 
| Daniel Veillard | b06c614 | 2001-08-27 14:26:30 +0000 | [diff] [blame] | 7551 | #endif | 
| Daniel Veillard | eca8281 | 2002-04-24 11:42:02 +0000 | [diff] [blame] | 7552 |     if (cur == NULL) return(0); | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7553 |     while (IS_BLANK_CH(*cur)) cur++; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7554 |     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { | 
 | 7555 |         return(xmlXPathNAN); | 
 | 7556 |     } | 
 | 7557 |     if (*cur == '-') { | 
 | 7558 | 	isneg = 1; | 
 | 7559 | 	cur++; | 
 | 7560 |     } | 
| Daniel Veillard | b06c614 | 2001-08-27 14:26:30 +0000 | [diff] [blame] | 7561 |  | 
 | 7562 | #ifdef __GNUC__ | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7563 |     /* | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7564 |      * tmp/temp is a workaround against a gcc compiler bug | 
 | 7565 |      * http://veillard.com/gcc.bug | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7566 |      */ | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7567 |     ret = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7568 |     while ((*cur >= '0') && (*cur <= '9')) { | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7569 | 	ret = ret * 10; | 
 | 7570 | 	tmp = (*cur - '0'); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7571 | 	ok = 1; | 
 | 7572 | 	cur++; | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7573 | 	temp = (double) tmp; | 
 | 7574 | 	ret = ret + temp; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7575 |     } | 
| Daniel Veillard | b06c614 | 2001-08-27 14:26:30 +0000 | [diff] [blame] | 7576 | #else | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7577 |     ret = 0; | 
| Daniel Veillard | b06c614 | 2001-08-27 14:26:30 +0000 | [diff] [blame] | 7578 |     while ((*cur >= '0') && (*cur <= '9')) { | 
 | 7579 | 	ret = ret * 10 + (*cur - '0'); | 
 | 7580 | 	ok = 1; | 
 | 7581 | 	cur++; | 
 | 7582 |     } | 
 | 7583 | #endif | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7584 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7585 |     if (*cur == '.') { | 
| Daniel Veillard | 3cd7240 | 2002-05-13 10:33:30 +0000 | [diff] [blame] | 7586 | 	int v, frac = 0; | 
 | 7587 | 	double fraction = 0; | 
 | 7588 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7589 |         cur++; | 
 | 7590 | 	if (((*cur < '0') || (*cur > '9')) && (!ok)) { | 
 | 7591 | 	    return(xmlXPathNAN); | 
 | 7592 | 	} | 
| Daniel Veillard | 3cd7240 | 2002-05-13 10:33:30 +0000 | [diff] [blame] | 7593 | 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { | 
 | 7594 | 	    v = (*cur - '0'); | 
 | 7595 | 	    fraction = fraction * 10 + v; | 
 | 7596 | 	    frac = frac + 1; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7597 | 	    cur++; | 
 | 7598 | 	} | 
| Daniel Veillard | 3cd7240 | 2002-05-13 10:33:30 +0000 | [diff] [blame] | 7599 | 	fraction /= my_pow10[frac]; | 
 | 7600 | 	ret = ret + fraction; | 
 | 7601 | 	while ((*cur >= '0') && (*cur <= '9')) | 
 | 7602 | 	    cur++; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7603 |     } | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7604 |     if ((*cur == 'e') || (*cur == 'E')) { | 
 | 7605 |       cur++; | 
 | 7606 |       if (*cur == '-') { | 
 | 7607 | 	is_exponent_negative = 1; | 
 | 7608 | 	cur++; | 
| William M. Brack | 9912705 | 2004-05-24 02:52:28 +0000 | [diff] [blame] | 7609 |       } else if (*cur == '+') { | 
 | 7610 |         cur++; | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7611 |       } | 
 | 7612 |       while ((*cur >= '0') && (*cur <= '9')) { | 
 | 7613 | 	exponent = exponent * 10 + (*cur - '0'); | 
 | 7614 | 	cur++; | 
 | 7615 |       } | 
 | 7616 |     } | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7617 |     while (IS_BLANK_CH(*cur)) cur++; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7618 |     if (*cur != 0) return(xmlXPathNAN); | 
 | 7619 |     if (isneg) ret = -ret; | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7620 |     if (is_exponent_negative) exponent = -exponent; | 
 | 7621 |     ret *= pow(10.0, (double)exponent); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7622 |     return(ret); | 
 | 7623 | } | 
 | 7624 |  | 
 | 7625 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7626 |  * xmlXPathCompNumber: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7627 |  * @ctxt:  the XPath Parser context | 
 | 7628 |  * | 
 | 7629 |  *  [30]   Number ::=   Digits ('.' Digits?)? | 
 | 7630 |  *                    | '.' Digits  | 
 | 7631 |  *  [31]   Digits ::=   [0-9]+ | 
 | 7632 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7633 |  * Compile a Number, then push it on the stack | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7634 |  * | 
 | 7635 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7636 | static void | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7637 | xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) | 
 | 7638 | { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7639 |     double ret = 0.0; | 
 | 7640 |     double mult = 1; | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7641 |     int ok = 0; | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7642 |     int exponent = 0; | 
 | 7643 |     int is_exponent_negative = 0; | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7644 | #ifdef __GNUC__ | 
 | 7645 |     unsigned long tmp = 0; | 
 | 7646 |     double temp; | 
 | 7647 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7648 |  | 
 | 7649 |     CHECK_ERROR; | 
 | 7650 |     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { | 
 | 7651 |         XP_ERROR(XPATH_NUMBER_ERROR); | 
 | 7652 |     } | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7653 | #ifdef __GNUC__ | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7654 |     /* | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7655 |      * tmp/temp is a workaround against a gcc compiler bug | 
 | 7656 |      * http://veillard.com/gcc.bug | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7657 |      */ | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7658 |     ret = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7659 |     while ((CUR >= '0') && (CUR <= '9')) { | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7660 | 	ret = ret * 10; | 
 | 7661 | 	tmp = (CUR - '0'); | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7662 |         ok = 1; | 
 | 7663 |         NEXT; | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7664 | 	temp = (double) tmp; | 
 | 7665 | 	ret = ret + temp; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7666 |     } | 
| Daniel Veillard | 7b41613 | 2002-03-07 08:36:03 +0000 | [diff] [blame] | 7667 | #else | 
 | 7668 |     ret = 0; | 
 | 7669 |     while ((CUR >= '0') && (CUR <= '9')) { | 
 | 7670 | 	ret = ret * 10 + (CUR - '0'); | 
 | 7671 | 	ok = 1; | 
 | 7672 | 	NEXT; | 
 | 7673 |     } | 
 | 7674 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7675 |     if (CUR == '.') { | 
 | 7676 |         NEXT; | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7677 |         if (((CUR < '0') || (CUR > '9')) && (!ok)) { | 
 | 7678 |             XP_ERROR(XPATH_NUMBER_ERROR); | 
 | 7679 |         } | 
 | 7680 |         while ((CUR >= '0') && (CUR <= '9')) { | 
 | 7681 |             mult /= 10; | 
 | 7682 |             ret = ret + (CUR - '0') * mult; | 
 | 7683 |             NEXT; | 
 | 7684 |         } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7685 |     } | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7686 |     if ((CUR == 'e') || (CUR == 'E')) { | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7687 |         NEXT; | 
 | 7688 |         if (CUR == '-') { | 
 | 7689 |             is_exponent_negative = 1; | 
 | 7690 |             NEXT; | 
| William M. Brack | 9912705 | 2004-05-24 02:52:28 +0000 | [diff] [blame] | 7691 |         } else if (CUR == '+') { | 
 | 7692 | 	    NEXT; | 
 | 7693 | 	} | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7694 |         while ((CUR >= '0') && (CUR <= '9')) { | 
 | 7695 |             exponent = exponent * 10 + (CUR - '0'); | 
 | 7696 |             NEXT; | 
 | 7697 |         } | 
 | 7698 |         if (is_exponent_negative) | 
 | 7699 |             exponent = -exponent; | 
 | 7700 |         ret *= pow(10.0, (double) exponent); | 
| Bjorn Reese | 70a9da5 | 2001-04-21 16:57:29 +0000 | [diff] [blame] | 7701 |     } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 7702 |     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, | 
| Daniel Veillard | d79bcd1 | 2001-06-21 22:07:42 +0000 | [diff] [blame] | 7703 |                    xmlXPathNewFloat(ret), NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7704 | } | 
 | 7705 |  | 
 | 7706 | /** | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 7707 |  * xmlXPathParseLiteral: | 
 | 7708 |  * @ctxt:  the XPath Parser context | 
 | 7709 |  * | 
 | 7710 |  * Parse a Literal | 
 | 7711 |  * | 
 | 7712 |  *  [29]   Literal ::=   '"' [^"]* '"' | 
 | 7713 |  *                    | "'" [^']* "'" | 
 | 7714 |  * | 
 | 7715 |  * Returns the value found or NULL in case of error | 
 | 7716 |  */ | 
 | 7717 | static xmlChar * | 
 | 7718 | xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { | 
 | 7719 |     const xmlChar *q; | 
 | 7720 |     xmlChar *ret = NULL; | 
 | 7721 |  | 
 | 7722 |     if (CUR == '"') { | 
 | 7723 |         NEXT; | 
 | 7724 | 	q = CUR_PTR; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7725 | 	while ((IS_CHAR_CH(CUR)) && (CUR != '"')) | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 7726 | 	    NEXT; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7727 | 	if (!IS_CHAR_CH(CUR)) { | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 7728 | 	    XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR); | 
 | 7729 | 	} else { | 
 | 7730 | 	    ret = xmlStrndup(q, CUR_PTR - q); | 
 | 7731 | 	    NEXT; | 
 | 7732 |         } | 
 | 7733 |     } else if (CUR == '\'') { | 
 | 7734 |         NEXT; | 
 | 7735 | 	q = CUR_PTR; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7736 | 	while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 7737 | 	    NEXT; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7738 | 	if (!IS_CHAR_CH(CUR)) { | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 7739 | 	    XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR); | 
 | 7740 | 	} else { | 
 | 7741 | 	    ret = xmlStrndup(q, CUR_PTR - q); | 
 | 7742 | 	    NEXT; | 
 | 7743 |         } | 
 | 7744 |     } else { | 
 | 7745 | 	XP_ERROR0(XPATH_START_LITERAL_ERROR); | 
 | 7746 |     } | 
 | 7747 |     return(ret); | 
 | 7748 | } | 
 | 7749 |  | 
 | 7750 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7751 |  * xmlXPathCompLiteral: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7752 |  * @ctxt:  the XPath Parser context | 
 | 7753 |  * | 
 | 7754 |  * Parse a Literal and push it on the stack. | 
 | 7755 |  * | 
 | 7756 |  *  [29]   Literal ::=   '"' [^"]* '"' | 
 | 7757 |  *                    | "'" [^']* "'" | 
 | 7758 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7759 |  * TODO: xmlXPathCompLiteral memory allocation could be improved. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7760 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7761 | static void | 
 | 7762 | xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7763 |     const xmlChar *q; | 
 | 7764 |     xmlChar *ret = NULL; | 
 | 7765 |  | 
 | 7766 |     if (CUR == '"') { | 
 | 7767 |         NEXT; | 
 | 7768 | 	q = CUR_PTR; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7769 | 	while ((IS_CHAR_CH(CUR)) && (CUR != '"')) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7770 | 	    NEXT; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7771 | 	if (!IS_CHAR_CH(CUR)) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7772 | 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); | 
 | 7773 | 	} else { | 
 | 7774 | 	    ret = xmlStrndup(q, CUR_PTR - q); | 
 | 7775 | 	    NEXT; | 
 | 7776 |         } | 
 | 7777 |     } else if (CUR == '\'') { | 
 | 7778 |         NEXT; | 
 | 7779 | 	q = CUR_PTR; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7780 | 	while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7781 | 	    NEXT; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 7782 | 	if (!IS_CHAR_CH(CUR)) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7783 | 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); | 
 | 7784 | 	} else { | 
 | 7785 | 	    ret = xmlStrndup(q, CUR_PTR - q); | 
 | 7786 | 	    NEXT; | 
 | 7787 |         } | 
 | 7788 |     } else { | 
 | 7789 | 	XP_ERROR(XPATH_START_LITERAL_ERROR); | 
 | 7790 |     } | 
 | 7791 |     if (ret == NULL) return; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 7792 |     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, | 
 | 7793 | 	           xmlXPathNewString(ret), NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7794 |     xmlFree(ret); | 
 | 7795 | } | 
 | 7796 |  | 
 | 7797 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7798 |  * xmlXPathCompVariableReference: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7799 |  * @ctxt:  the XPath Parser context | 
 | 7800 |  * | 
 | 7801 |  * Parse a VariableReference, evaluate it and push it on the stack. | 
 | 7802 |  * | 
 | 7803 |  * The variable bindings consist of a mapping from variable names | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 7804 |  * to variable values. The value of a variable is an object, which can be | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7805 |  * of any of the types that are possible for the value of an expression, | 
 | 7806 |  * and may also be of additional types not specified here. | 
 | 7807 |  * | 
 | 7808 |  * Early evaluation is possible since: | 
 | 7809 |  * The variable bindings [...] used to evaluate a subexpression are | 
 | 7810 |  * always the same as those used to evaluate the containing expression.  | 
 | 7811 |  * | 
 | 7812 |  *  [36]   VariableReference ::=   '$' QName  | 
 | 7813 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7814 | static void | 
 | 7815 | xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7816 |     xmlChar *name; | 
 | 7817 |     xmlChar *prefix; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7818 |  | 
 | 7819 |     SKIP_BLANKS; | 
 | 7820 |     if (CUR != '$') { | 
 | 7821 | 	XP_ERROR(XPATH_VARIABLE_REF_ERROR); | 
 | 7822 |     } | 
 | 7823 |     NEXT; | 
 | 7824 |     name = xmlXPathParseQName(ctxt, &prefix); | 
 | 7825 |     if (name == NULL) { | 
 | 7826 | 	XP_ERROR(XPATH_VARIABLE_REF_ERROR); | 
 | 7827 |     } | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 7828 |     ctxt->comp->last = -1; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 7829 |     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, | 
 | 7830 | 	           name, prefix); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7831 |     SKIP_BLANKS; | 
 | 7832 | } | 
 | 7833 |  | 
 | 7834 | /** | 
 | 7835 |  * xmlXPathIsNodeType: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7836 |  * @name:  a name string | 
 | 7837 |  * | 
 | 7838 |  * Is the name given a NodeType one. | 
 | 7839 |  * | 
 | 7840 |  *  [38]   NodeType ::=   'comment' | 
 | 7841 |  *                    | 'text' | 
 | 7842 |  *                    | 'processing-instruction' | 
 | 7843 |  *                    | 'node' | 
 | 7844 |  * | 
 | 7845 |  * Returns 1 if true 0 otherwise | 
 | 7846 |  */ | 
 | 7847 | int | 
 | 7848 | xmlXPathIsNodeType(const xmlChar *name) { | 
 | 7849 |     if (name == NULL) | 
 | 7850 | 	return(0); | 
 | 7851 |  | 
| Daniel Veillard | 1971ee2 | 2002-01-31 20:29:19 +0000 | [diff] [blame] | 7852 |     if (xmlStrEqual(name, BAD_CAST "node")) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7853 | 	return(1); | 
 | 7854 |     if (xmlStrEqual(name, BAD_CAST "text")) | 
 | 7855 | 	return(1); | 
| Daniel Veillard | 1971ee2 | 2002-01-31 20:29:19 +0000 | [diff] [blame] | 7856 |     if (xmlStrEqual(name, BAD_CAST "comment")) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7857 | 	return(1); | 
| Daniel Veillard | 1971ee2 | 2002-01-31 20:29:19 +0000 | [diff] [blame] | 7858 |     if (xmlStrEqual(name, BAD_CAST "processing-instruction")) | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7859 | 	return(1); | 
 | 7860 |     return(0); | 
 | 7861 | } | 
 | 7862 |  | 
 | 7863 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7864 |  * xmlXPathCompFunctionCall: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7865 |  * @ctxt:  the XPath Parser context | 
 | 7866 |  * | 
 | 7867 |  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')' | 
 | 7868 |  *  [17]   Argument ::=   Expr  | 
 | 7869 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7870 |  * Compile a function call, the evaluation of all arguments are | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7871 |  * pushed on the stack | 
 | 7872 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7873 | static void | 
 | 7874 | xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7875 |     xmlChar *name; | 
 | 7876 |     xmlChar *prefix; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7877 |     int nbargs = 0; | 
 | 7878 |  | 
 | 7879 |     name = xmlXPathParseQName(ctxt, &prefix); | 
 | 7880 |     if (name == NULL) { | 
 | 7881 | 	XP_ERROR(XPATH_EXPR_ERROR); | 
 | 7882 |     } | 
 | 7883 |     SKIP_BLANKS; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7884 | #ifdef DEBUG_EXPR | 
 | 7885 |     if (prefix == NULL) | 
 | 7886 | 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", | 
 | 7887 | 			name); | 
 | 7888 |     else | 
 | 7889 | 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", | 
 | 7890 | 			prefix, name); | 
 | 7891 | #endif | 
 | 7892 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7893 |     if (CUR != '(') { | 
 | 7894 | 	XP_ERROR(XPATH_EXPR_ERROR); | 
 | 7895 |     } | 
 | 7896 |     NEXT; | 
 | 7897 |     SKIP_BLANKS; | 
 | 7898 |  | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 7899 |     ctxt->comp->last = -1; | 
| Daniel Veillard | 71f9d73 | 2003-01-14 16:07:16 +0000 | [diff] [blame] | 7900 |     if (CUR != ')') { | 
 | 7901 | 	while (CUR != 0) { | 
 | 7902 | 	    int op1 = ctxt->comp->last; | 
 | 7903 | 	    ctxt->comp->last = -1; | 
 | 7904 | 	    xmlXPathCompileExpr(ctxt); | 
 | 7905 | 	    CHECK_ERROR; | 
 | 7906 | 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); | 
 | 7907 | 	    nbargs++; | 
 | 7908 | 	    if (CUR == ')') break; | 
 | 7909 | 	    if (CUR != ',') { | 
 | 7910 | 		XP_ERROR(XPATH_EXPR_ERROR); | 
 | 7911 | 	    } | 
 | 7912 | 	    NEXT; | 
 | 7913 | 	    SKIP_BLANKS; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7914 | 	} | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7915 |     } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 7916 |     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, | 
 | 7917 | 	           name, prefix); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7918 |     NEXT; | 
 | 7919 |     SKIP_BLANKS; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7920 | } | 
 | 7921 |  | 
 | 7922 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7923 |  * xmlXPathCompPrimaryExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7924 |  * @ctxt:  the XPath Parser context | 
 | 7925 |  * | 
 | 7926 |  *  [15]   PrimaryExpr ::=   VariableReference  | 
 | 7927 |  *                | '(' Expr ')' | 
 | 7928 |  *                | Literal  | 
 | 7929 |  *                | Number  | 
 | 7930 |  *                | FunctionCall  | 
 | 7931 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7932 |  * Compile a primary expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7933 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7934 | static void | 
 | 7935 | xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7936 |     SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7937 |     if (CUR == '$') xmlXPathCompVariableReference(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7938 |     else if (CUR == '(') { | 
 | 7939 | 	NEXT; | 
 | 7940 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7941 | 	xmlXPathCompileExpr(ctxt); | 
| Aleksey Sanin | 50fe8b1 | 2002-05-07 16:21:36 +0000 | [diff] [blame] | 7942 | 	CHECK_ERROR; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7943 | 	if (CUR != ')') { | 
 | 7944 | 	    XP_ERROR(XPATH_EXPR_ERROR); | 
 | 7945 | 	} | 
 | 7946 | 	NEXT; | 
 | 7947 | 	SKIP_BLANKS; | 
| William M. Brack | d1757ab | 2004-10-02 22:07:48 +0000 | [diff] [blame] | 7948 |     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7949 | 	xmlXPathCompNumber(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7950 |     } else if ((CUR == '\'') || (CUR == '"')) { | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7951 | 	xmlXPathCompLiteral(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7952 |     } else { | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7953 | 	xmlXPathCompFunctionCall(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7954 |     } | 
 | 7955 |     SKIP_BLANKS; | 
 | 7956 | } | 
 | 7957 |  | 
 | 7958 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7959 |  * xmlXPathCompFilterExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7960 |  * @ctxt:  the XPath Parser context | 
 | 7961 |  * | 
 | 7962 |  *  [20]   FilterExpr ::=   PrimaryExpr  | 
 | 7963 |  *               | FilterExpr Predicate  | 
 | 7964 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7965 |  * Compile a filter expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7966 |  * Square brackets are used to filter expressions in the same way that | 
 | 7967 |  * they are used in location paths. It is an error if the expression to | 
 | 7968 |  * be filtered does not evaluate to a node-set. The context node list | 
 | 7969 |  * used for evaluating the expression in square brackets is the node-set | 
 | 7970 |  * to be filtered listed in document order. | 
 | 7971 |  */ | 
 | 7972 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 7973 | static void | 
 | 7974 | xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { | 
 | 7975 |     xmlXPathCompPrimaryExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7976 |     CHECK_ERROR; | 
 | 7977 |     SKIP_BLANKS; | 
 | 7978 |      | 
 | 7979 |     while (CUR == '[') { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 7980 | 	xmlXPathCompPredicate(ctxt, 1); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 7981 | 	SKIP_BLANKS; | 
 | 7982 |     } | 
 | 7983 |  | 
 | 7984 |      | 
 | 7985 | } | 
 | 7986 |  | 
 | 7987 | /** | 
 | 7988 |  * xmlXPathScanName: | 
 | 7989 |  * @ctxt:  the XPath Parser context | 
 | 7990 |  * | 
 | 7991 |  * Trickery: parse an XML name but without consuming the input flow | 
 | 7992 |  * Needed to avoid insanity in the parser state. | 
 | 7993 |  * | 
 | 7994 |  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | | 
 | 7995 |  *                  CombiningChar | Extender | 
 | 7996 |  * | 
 | 7997 |  * [5] Name ::= (Letter | '_' | ':') (NameChar)* | 
 | 7998 |  * | 
 | 7999 |  * [6] Names ::= Name (S Name)* | 
 | 8000 |  * | 
 | 8001 |  * Returns the Name parsed or NULL | 
 | 8002 |  */ | 
 | 8003 |  | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 8004 | static xmlChar * | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8005 | xmlXPathScanName(xmlXPathParserContextPtr ctxt) { | 
| Daniel Veillard | 0322681 | 2004-11-01 14:55:21 +0000 | [diff] [blame] | 8006 |     int len = 0, l; | 
 | 8007 |     int c; | 
| Daniel Veillard | 0322681 | 2004-11-01 14:55:21 +0000 | [diff] [blame] | 8008 |     const xmlChar *cur; | 
 | 8009 |     xmlChar *ret; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8010 |  | 
| Daniel Veillard | 0322681 | 2004-11-01 14:55:21 +0000 | [diff] [blame] | 8011 |     cur = ctxt->cur; | 
 | 8012 |  | 
 | 8013 |     c = CUR_CHAR(l); | 
 | 8014 |     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ | 
 | 8015 | 	(!IS_LETTER(c) && (c != '_') && | 
 | 8016 |          (c != ':'))) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8017 | 	return(NULL); | 
 | 8018 |     } | 
 | 8019 |  | 
| Daniel Veillard | 0322681 | 2004-11-01 14:55:21 +0000 | [diff] [blame] | 8020 |     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ | 
 | 8021 | 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) || | 
 | 8022 |             (c == '.') || (c == '-') || | 
 | 8023 | 	    (c == '_') || (c == ':') ||  | 
 | 8024 | 	    (IS_COMBINING(c)) || | 
 | 8025 | 	    (IS_EXTENDER(c)))) { | 
 | 8026 | 	len += l; | 
 | 8027 | 	NEXTL(l); | 
 | 8028 | 	c = CUR_CHAR(l); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8029 |     } | 
| Daniel Veillard | 0322681 | 2004-11-01 14:55:21 +0000 | [diff] [blame] | 8030 |     ret = xmlStrndup(cur, ctxt->cur - cur); | 
 | 8031 |     ctxt->cur = cur; | 
 | 8032 |     return(ret); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8033 | } | 
 | 8034 |  | 
 | 8035 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8036 |  * xmlXPathCompPathExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8037 |  * @ctxt:  the XPath Parser context | 
 | 8038 |  * | 
 | 8039 |  *  [19]   PathExpr ::=   LocationPath  | 
 | 8040 |  *               | FilterExpr  | 
 | 8041 |  *               | FilterExpr '/' RelativeLocationPath  | 
 | 8042 |  *               | FilterExpr '//' RelativeLocationPath  | 
 | 8043 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8044 |  * Compile a path expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8045 |  * The / operator and // operators combine an arbitrary expression | 
 | 8046 |  * and a relative location path. It is an error if the expression | 
 | 8047 |  * does not evaluate to a node-set. | 
 | 8048 |  * The / operator does composition in the same way as when / is | 
 | 8049 |  * used in a location path. As in location paths, // is short for | 
 | 8050 |  * /descendant-or-self::node()/. | 
 | 8051 |  */ | 
 | 8052 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8053 | static void | 
 | 8054 | xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8055 |     int lc = 1;           /* Should we branch to LocationPath ?         */ | 
 | 8056 |     xmlChar *name = NULL; /* we may have to preparse a name to find out */ | 
 | 8057 |  | 
 | 8058 |     SKIP_BLANKS; | 
| William M. Brack | d1757ab | 2004-10-02 22:07:48 +0000 | [diff] [blame] | 8059 |     if ((CUR == '$') || (CUR == '(') ||  | 
 | 8060 |     	(IS_ASCII_DIGIT(CUR)) || | 
 | 8061 |         (CUR == '\'') || (CUR == '"') || | 
 | 8062 | 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8063 | 	lc = 0; | 
 | 8064 |     } else if (CUR == '*') { | 
 | 8065 | 	/* relative or absolute location path */ | 
 | 8066 | 	lc = 1; | 
 | 8067 |     } else if (CUR == '/') { | 
 | 8068 | 	/* relative or absolute location path */ | 
 | 8069 | 	lc = 1; | 
 | 8070 |     } else if (CUR == '@') { | 
 | 8071 | 	/* relative abbreviated attribute location path */ | 
 | 8072 | 	lc = 1; | 
 | 8073 |     } else if (CUR == '.') { | 
 | 8074 | 	/* relative abbreviated attribute location path */ | 
 | 8075 | 	lc = 1; | 
 | 8076 |     } else { | 
 | 8077 | 	/* | 
 | 8078 | 	 * Problem is finding if we have a name here whether it's: | 
 | 8079 | 	 *   - a nodetype | 
 | 8080 | 	 *   - a function call in which case it's followed by '(' | 
 | 8081 | 	 *   - an axis in which case it's followed by ':' | 
 | 8082 | 	 *   - a element name | 
 | 8083 | 	 * We do an a priori analysis here rather than having to | 
 | 8084 | 	 * maintain parsed token content through the recursive function | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 8085 | 	 * calls. This looks uglier but makes the code easier to | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8086 | 	 * read/write/debug. | 
 | 8087 | 	 */ | 
 | 8088 | 	SKIP_BLANKS; | 
 | 8089 | 	name = xmlXPathScanName(ctxt); | 
 | 8090 | 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { | 
 | 8091 | #ifdef DEBUG_STEP | 
 | 8092 | 	    xmlGenericError(xmlGenericErrorContext, | 
 | 8093 | 		    "PathExpr: Axis\n"); | 
 | 8094 | #endif | 
 | 8095 | 	    lc = 1; | 
 | 8096 | 	    xmlFree(name); | 
 | 8097 | 	} else if (name != NULL) { | 
 | 8098 | 	    int len =xmlStrlen(name); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8099 |  | 
 | 8100 | 	     | 
 | 8101 | 	    while (NXT(len) != 0) { | 
 | 8102 | 		if (NXT(len) == '/') { | 
 | 8103 | 		    /* element name */ | 
 | 8104 | #ifdef DEBUG_STEP | 
 | 8105 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 8106 | 			    "PathExpr: AbbrRelLocation\n"); | 
 | 8107 | #endif | 
 | 8108 | 		    lc = 1; | 
 | 8109 | 		    break; | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 8110 | 		} else if (IS_BLANK_CH(NXT(len))) { | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 8111 | 		    /* ignore blanks */ | 
 | 8112 | 		    ; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8113 | 		} else if (NXT(len) == ':') { | 
 | 8114 | #ifdef DEBUG_STEP | 
 | 8115 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 8116 | 			    "PathExpr: AbbrRelLocation\n"); | 
 | 8117 | #endif | 
 | 8118 | 		    lc = 1; | 
 | 8119 | 		    break; | 
 | 8120 | 		} else if ((NXT(len) == '(')) { | 
 | 8121 | 		    /* Note Type or Function */ | 
 | 8122 | 		    if (xmlXPathIsNodeType(name)) { | 
 | 8123 | #ifdef DEBUG_STEP | 
 | 8124 | 		        xmlGenericError(xmlGenericErrorContext, | 
 | 8125 | 				"PathExpr: Type search\n"); | 
 | 8126 | #endif | 
 | 8127 | 			lc = 1; | 
 | 8128 | 		    } else { | 
 | 8129 | #ifdef DEBUG_STEP | 
 | 8130 | 		        xmlGenericError(xmlGenericErrorContext, | 
 | 8131 | 				"PathExpr: function call\n"); | 
 | 8132 | #endif | 
 | 8133 | 			lc = 0; | 
 | 8134 | 		    } | 
 | 8135 |                     break; | 
 | 8136 | 		} else if ((NXT(len) == '[')) { | 
 | 8137 | 		    /* element name */ | 
 | 8138 | #ifdef DEBUG_STEP | 
 | 8139 | 		    xmlGenericError(xmlGenericErrorContext, | 
 | 8140 | 			    "PathExpr: AbbrRelLocation\n"); | 
 | 8141 | #endif | 
 | 8142 | 		    lc = 1; | 
 | 8143 | 		    break; | 
 | 8144 | 		} else if ((NXT(len) == '<') || (NXT(len) == '>') || | 
 | 8145 | 			   (NXT(len) == '=')) { | 
 | 8146 | 		    lc = 1; | 
 | 8147 | 		    break; | 
 | 8148 | 		} else { | 
 | 8149 | 		    lc = 1; | 
 | 8150 | 		    break; | 
 | 8151 | 		} | 
 | 8152 | 		len++; | 
 | 8153 | 	    } | 
 | 8154 | 	    if (NXT(len) == 0) { | 
 | 8155 | #ifdef DEBUG_STEP | 
 | 8156 | 		xmlGenericError(xmlGenericErrorContext, | 
 | 8157 | 			"PathExpr: AbbrRelLocation\n"); | 
 | 8158 | #endif | 
 | 8159 | 		/* element name */ | 
 | 8160 | 		lc = 1; | 
 | 8161 | 	    } | 
 | 8162 | 	    xmlFree(name); | 
 | 8163 | 	} else { | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 8164 | 	    /* make sure all cases are covered explicitly */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8165 | 	    XP_ERROR(XPATH_EXPR_ERROR); | 
 | 8166 | 	} | 
 | 8167 |     }  | 
 | 8168 |  | 
 | 8169 |     if (lc) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8170 | 	if (CUR == '/') { | 
 | 8171 | 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); | 
 | 8172 | 	} else { | 
 | 8173 | 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8174 | 	} | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8175 | 	xmlXPathCompLocationPath(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8176 |     } else { | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8177 | 	xmlXPathCompFilterExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8178 | 	CHECK_ERROR; | 
 | 8179 | 	if ((CUR == '/') && (NXT(1) == '/')) { | 
 | 8180 | 	    SKIP(2); | 
 | 8181 | 	    SKIP_BLANKS; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8182 |  | 
 | 8183 | 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, | 
 | 8184 | 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); | 
 | 8185 | 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); | 
 | 8186 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8187 | 	    xmlXPathCompRelativeLocationPath(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8188 | 	} else if (CUR == '/') { | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8189 | 	    xmlXPathCompRelativeLocationPath(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8190 | 	} | 
 | 8191 |     } | 
 | 8192 |     SKIP_BLANKS; | 
 | 8193 | } | 
 | 8194 |  | 
 | 8195 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8196 |  * xmlXPathCompUnionExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8197 |  * @ctxt:  the XPath Parser context | 
 | 8198 |  * | 
 | 8199 |  *  [18]   UnionExpr ::=   PathExpr  | 
 | 8200 |  *               | UnionExpr '|' PathExpr  | 
 | 8201 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8202 |  * Compile an union expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8203 |  */ | 
 | 8204 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8205 | static void | 
 | 8206 | xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { | 
 | 8207 |     xmlXPathCompPathExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8208 |     CHECK_ERROR; | 
 | 8209 |     SKIP_BLANKS; | 
 | 8210 |     while (CUR == '|') { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8211 | 	int op1 = ctxt->comp->last; | 
 | 8212 | 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8213 |  | 
 | 8214 | 	NEXT; | 
 | 8215 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8216 | 	xmlXPathCompPathExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8217 |  | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8218 | 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); | 
 | 8219 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8220 | 	SKIP_BLANKS; | 
 | 8221 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8222 | } | 
 | 8223 |  | 
 | 8224 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8225 |  * xmlXPathCompUnaryExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8226 |  * @ctxt:  the XPath Parser context | 
 | 8227 |  * | 
 | 8228 |  *  [27]   UnaryExpr ::=   UnionExpr  | 
 | 8229 |  *                   | '-' UnaryExpr  | 
 | 8230 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8231 |  * Compile an unary expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8232 |  */ | 
 | 8233 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8234 | static void | 
 | 8235 | xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8236 |     int minus = 0; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8237 |     int found = 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8238 |  | 
 | 8239 |     SKIP_BLANKS; | 
| Daniel Veillard | 68d7b67 | 2001-03-12 18:22:04 +0000 | [diff] [blame] | 8240 |     while (CUR == '-') { | 
 | 8241 |         minus = 1 - minus; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8242 | 	found = 1; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8243 | 	NEXT; | 
 | 8244 | 	SKIP_BLANKS; | 
 | 8245 |     } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8246 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8247 |     xmlXPathCompUnionExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8248 |     CHECK_ERROR; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8249 |     if (found) { | 
 | 8250 | 	if (minus) | 
 | 8251 | 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); | 
 | 8252 | 	else | 
 | 8253 | 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8254 |     } | 
 | 8255 | } | 
 | 8256 |  | 
 | 8257 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8258 |  * xmlXPathCompMultiplicativeExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8259 |  * @ctxt:  the XPath Parser context | 
 | 8260 |  * | 
 | 8261 |  *  [26]   MultiplicativeExpr ::=   UnaryExpr  | 
 | 8262 |  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr  | 
 | 8263 |  *                   | MultiplicativeExpr 'div' UnaryExpr  | 
 | 8264 |  *                   | MultiplicativeExpr 'mod' UnaryExpr  | 
 | 8265 |  *  [34]   MultiplyOperator ::=   '*' | 
 | 8266 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8267 |  * Compile an Additive expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8268 |  */ | 
 | 8269 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8270 | static void | 
 | 8271 | xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { | 
 | 8272 |     xmlXPathCompUnaryExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8273 |     CHECK_ERROR; | 
 | 8274 |     SKIP_BLANKS; | 
 | 8275 |     while ((CUR == '*') ||  | 
 | 8276 |            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || | 
 | 8277 |            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { | 
 | 8278 | 	int op = -1; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8279 | 	int op1 = ctxt->comp->last; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8280 |  | 
 | 8281 |         if (CUR == '*') { | 
 | 8282 | 	    op = 0; | 
 | 8283 | 	    NEXT; | 
 | 8284 | 	} else if (CUR == 'd') { | 
 | 8285 | 	    op = 1; | 
 | 8286 | 	    SKIP(3); | 
 | 8287 | 	} else if (CUR == 'm') { | 
 | 8288 | 	    op = 2; | 
 | 8289 | 	    SKIP(3); | 
 | 8290 | 	} | 
 | 8291 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8292 |         xmlXPathCompUnaryExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8293 | 	CHECK_ERROR; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8294 | 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8295 | 	SKIP_BLANKS; | 
 | 8296 |     } | 
 | 8297 | } | 
 | 8298 |  | 
 | 8299 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8300 |  * xmlXPathCompAdditiveExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8301 |  * @ctxt:  the XPath Parser context | 
 | 8302 |  * | 
 | 8303 |  *  [25]   AdditiveExpr ::=   MultiplicativeExpr  | 
 | 8304 |  *                   | AdditiveExpr '+' MultiplicativeExpr  | 
 | 8305 |  *                   | AdditiveExpr '-' MultiplicativeExpr  | 
 | 8306 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8307 |  * Compile an Additive expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8308 |  */ | 
 | 8309 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8310 | static void | 
 | 8311 | xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8312 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8313 |     xmlXPathCompMultiplicativeExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8314 |     CHECK_ERROR; | 
 | 8315 |     SKIP_BLANKS; | 
 | 8316 |     while ((CUR == '+') || (CUR == '-')) { | 
 | 8317 | 	int plus; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8318 | 	int op1 = ctxt->comp->last; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8319 |  | 
 | 8320 |         if (CUR == '+') plus = 1; | 
 | 8321 | 	else plus = 0; | 
 | 8322 | 	NEXT; | 
 | 8323 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8324 |         xmlXPathCompMultiplicativeExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8325 | 	CHECK_ERROR; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8326 | 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8327 | 	SKIP_BLANKS; | 
 | 8328 |     } | 
 | 8329 | } | 
 | 8330 |  | 
 | 8331 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8332 |  * xmlXPathCompRelationalExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8333 |  * @ctxt:  the XPath Parser context | 
 | 8334 |  * | 
 | 8335 |  *  [24]   RelationalExpr ::=   AdditiveExpr  | 
 | 8336 |  *                 | RelationalExpr '<' AdditiveExpr  | 
 | 8337 |  *                 | RelationalExpr '>' AdditiveExpr  | 
 | 8338 |  *                 | RelationalExpr '<=' AdditiveExpr  | 
 | 8339 |  *                 | RelationalExpr '>=' AdditiveExpr  | 
 | 8340 |  * | 
 | 8341 |  *  A <= B > C is allowed ? Answer from James, yes with | 
 | 8342 |  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr | 
 | 8343 |  *  which is basically what got implemented. | 
 | 8344 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8345 |  * Compile a Relational expression, then push the result | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8346 |  * on the stack | 
 | 8347 |  */ | 
 | 8348 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8349 | static void | 
 | 8350 | xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { | 
 | 8351 |     xmlXPathCompAdditiveExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8352 |     CHECK_ERROR; | 
 | 8353 |     SKIP_BLANKS; | 
 | 8354 |     while ((CUR == '<') || | 
 | 8355 |            (CUR == '>') || | 
 | 8356 |            ((CUR == '<') && (NXT(1) == '=')) || | 
 | 8357 |            ((CUR == '>') && (NXT(1) == '='))) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8358 | 	int inf, strict; | 
 | 8359 | 	int op1 = ctxt->comp->last; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8360 |  | 
 | 8361 |         if (CUR == '<') inf = 1; | 
 | 8362 | 	else inf = 0; | 
 | 8363 | 	if (NXT(1) == '=') strict = 0; | 
 | 8364 | 	else strict = 1; | 
 | 8365 | 	NEXT; | 
 | 8366 | 	if (!strict) NEXT; | 
 | 8367 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8368 |         xmlXPathCompAdditiveExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8369 | 	CHECK_ERROR; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8370 | 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8371 | 	SKIP_BLANKS; | 
 | 8372 |     } | 
 | 8373 | } | 
 | 8374 |  | 
 | 8375 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8376 |  * xmlXPathCompEqualityExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8377 |  * @ctxt:  the XPath Parser context | 
 | 8378 |  * | 
 | 8379 |  *  [23]   EqualityExpr ::=   RelationalExpr  | 
 | 8380 |  *                 | EqualityExpr '=' RelationalExpr  | 
 | 8381 |  *                 | EqualityExpr '!=' RelationalExpr  | 
 | 8382 |  * | 
 | 8383 |  *  A != B != C is allowed ? Answer from James, yes with | 
 | 8384 |  *  (RelationalExpr = RelationalExpr) = RelationalExpr | 
 | 8385 |  *  (RelationalExpr != RelationalExpr) != RelationalExpr | 
 | 8386 |  *  which is basically what got implemented. | 
 | 8387 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8388 |  * Compile an Equality expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8389 |  * | 
 | 8390 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8391 | static void | 
 | 8392 | xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { | 
 | 8393 |     xmlXPathCompRelationalExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8394 |     CHECK_ERROR; | 
 | 8395 |     SKIP_BLANKS; | 
 | 8396 |     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8397 | 	int eq; | 
 | 8398 | 	int op1 = ctxt->comp->last; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8399 |  | 
 | 8400 |         if (CUR == '=') eq = 1; | 
 | 8401 | 	else eq = 0; | 
 | 8402 | 	NEXT; | 
 | 8403 | 	if (!eq) NEXT; | 
 | 8404 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8405 |         xmlXPathCompRelationalExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8406 | 	CHECK_ERROR; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8407 | 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8408 | 	SKIP_BLANKS; | 
 | 8409 |     } | 
 | 8410 | } | 
 | 8411 |  | 
 | 8412 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8413 |  * xmlXPathCompAndExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8414 |  * @ctxt:  the XPath Parser context | 
 | 8415 |  * | 
 | 8416 |  *  [22]   AndExpr ::=   EqualityExpr  | 
 | 8417 |  *                 | AndExpr 'and' EqualityExpr  | 
 | 8418 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8419 |  * Compile an AND expression. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8420 |  * | 
 | 8421 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8422 | static void | 
 | 8423 | xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { | 
 | 8424 |     xmlXPathCompEqualityExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8425 |     CHECK_ERROR; | 
 | 8426 |     SKIP_BLANKS; | 
 | 8427 |     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8428 | 	int op1 = ctxt->comp->last; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8429 |         SKIP(3); | 
 | 8430 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8431 |         xmlXPathCompEqualityExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8432 | 	CHECK_ERROR; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8433 | 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8434 | 	SKIP_BLANKS; | 
 | 8435 |     } | 
 | 8436 | } | 
 | 8437 |  | 
 | 8438 | /** | 
| Daniel Veillard | 591b4be | 2003-02-09 23:33:36 +0000 | [diff] [blame] | 8439 |  * xmlXPathCompileExpr: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8440 |  * @ctxt:  the XPath Parser context | 
 | 8441 |  * | 
 | 8442 |  *  [14]   Expr ::=   OrExpr  | 
 | 8443 |  *  [21]   OrExpr ::=   AndExpr  | 
 | 8444 |  *                 | OrExpr 'or' AndExpr  | 
 | 8445 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8446 |  * Parse and compile an expression | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8447 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8448 | static void | 
 | 8449 | xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) { | 
 | 8450 |     xmlXPathCompAndExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8451 |     CHECK_ERROR; | 
 | 8452 |     SKIP_BLANKS; | 
 | 8453 |     while ((CUR == 'o') && (NXT(1) == 'r')) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8454 | 	int op1 = ctxt->comp->last; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8455 |         SKIP(2); | 
 | 8456 | 	SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8457 |         xmlXPathCompAndExpr(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8458 | 	CHECK_ERROR; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8459 | 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); | 
 | 8460 | 	op1 = ctxt->comp->nbStep; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8461 | 	SKIP_BLANKS; | 
 | 8462 |     } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8463 |     if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) { | 
 | 8464 | 	/* more ops could be optimized too */ | 
 | 8465 | 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); | 
 | 8466 |     } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8467 | } | 
 | 8468 |  | 
 | 8469 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8470 |  * xmlXPathCompPredicate: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8471 |  * @ctxt:  the XPath Parser context | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8472 |  * @filter:  act as a filter | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8473 |  * | 
 | 8474 |  *  [8]   Predicate ::=   '[' PredicateExpr ']' | 
 | 8475 |  *  [9]   PredicateExpr ::=   Expr  | 
 | 8476 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8477 |  * Compile a predicate expression | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8478 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8479 | static void | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8480 | xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8481 |     int op1 = ctxt->comp->last; | 
 | 8482 |  | 
 | 8483 |     SKIP_BLANKS; | 
 | 8484 |     if (CUR != '[') { | 
 | 8485 | 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); | 
 | 8486 |     } | 
 | 8487 |     NEXT; | 
 | 8488 |     SKIP_BLANKS; | 
 | 8489 |  | 
 | 8490 |     ctxt->comp->last = -1; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8491 |     xmlXPathCompileExpr(ctxt); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8492 |     CHECK_ERROR; | 
 | 8493 |  | 
 | 8494 |     if (CUR != ']') { | 
 | 8495 | 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); | 
 | 8496 |     } | 
 | 8497 |  | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8498 |     if (filter) | 
 | 8499 | 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); | 
 | 8500 |     else | 
 | 8501 | 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8502 |  | 
 | 8503 |     NEXT; | 
 | 8504 |     SKIP_BLANKS; | 
 | 8505 | } | 
 | 8506 |  | 
 | 8507 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8508 |  * xmlXPathCompNodeTest: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8509 |  * @ctxt:  the XPath Parser context | 
 | 8510 |  * @test:  pointer to a xmlXPathTestVal | 
 | 8511 |  * @type:  pointer to a xmlXPathTypeVal | 
 | 8512 |  * @prefix:  placeholder for a possible name prefix | 
 | 8513 |  * | 
 | 8514 |  * [7] NodeTest ::=   NameTest | 
 | 8515 |  *		    | NodeType '(' ')' | 
 | 8516 |  *		    | 'processing-instruction' '(' Literal ')' | 
 | 8517 |  * | 
 | 8518 |  * [37] NameTest ::=  '*' | 
 | 8519 |  *		    | NCName ':' '*' | 
 | 8520 |  *		    | QName | 
 | 8521 |  * [38] NodeType ::= 'comment' | 
 | 8522 |  *		   | 'text' | 
 | 8523 |  *		   | 'processing-instruction' | 
 | 8524 |  *		   | 'node' | 
 | 8525 |  * | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 8526 |  * Returns the name found and updates @test, @type and @prefix appropriately | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8527 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 8528 | static xmlChar * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8529 | xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, | 
 | 8530 | 	             xmlXPathTypeVal *type, const xmlChar **prefix, | 
 | 8531 | 		     xmlChar *name) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8532 |     int blanks; | 
 | 8533 |  | 
 | 8534 |     if ((test == NULL) || (type == NULL) || (prefix == NULL)) { | 
 | 8535 | 	STRANGE; | 
 | 8536 | 	return(NULL); | 
 | 8537 |     } | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 8538 |     *type = (xmlXPathTypeVal) 0; | 
 | 8539 |     *test = (xmlXPathTestVal) 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8540 |     *prefix = NULL; | 
 | 8541 |     SKIP_BLANKS; | 
 | 8542 |  | 
 | 8543 |     if ((name == NULL) && (CUR == '*')) { | 
 | 8544 | 	/* | 
 | 8545 | 	 * All elements | 
 | 8546 | 	 */ | 
 | 8547 | 	NEXT; | 
 | 8548 | 	*test = NODE_TEST_ALL; | 
 | 8549 | 	return(NULL); | 
 | 8550 |     } | 
 | 8551 |  | 
 | 8552 |     if (name == NULL) | 
 | 8553 | 	name = xmlXPathParseNCName(ctxt); | 
 | 8554 |     if (name == NULL) { | 
 | 8555 | 	XP_ERROR0(XPATH_EXPR_ERROR); | 
 | 8556 |     } | 
 | 8557 |  | 
| William M. Brack | 76e95df | 2003-10-18 16:20:14 +0000 | [diff] [blame] | 8558 |     blanks = IS_BLANK_CH(CUR); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8559 |     SKIP_BLANKS; | 
 | 8560 |     if (CUR == '(') { | 
 | 8561 | 	NEXT; | 
 | 8562 | 	/* | 
 | 8563 | 	 * NodeType or PI search | 
 | 8564 | 	 */ | 
 | 8565 | 	if (xmlStrEqual(name, BAD_CAST "comment")) | 
 | 8566 | 	    *type = NODE_TYPE_COMMENT; | 
 | 8567 | 	else if (xmlStrEqual(name, BAD_CAST "node")) | 
 | 8568 | 	    *type = NODE_TYPE_NODE; | 
 | 8569 | 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) | 
 | 8570 | 	    *type = NODE_TYPE_PI; | 
 | 8571 | 	else if (xmlStrEqual(name, BAD_CAST "text")) | 
 | 8572 | 	    *type = NODE_TYPE_TEXT; | 
 | 8573 | 	else { | 
 | 8574 | 	    if (name != NULL) | 
 | 8575 | 		xmlFree(name); | 
 | 8576 | 	    XP_ERROR0(XPATH_EXPR_ERROR); | 
 | 8577 | 	} | 
 | 8578 |  | 
 | 8579 | 	*test = NODE_TEST_TYPE; | 
 | 8580 | 	 | 
 | 8581 | 	SKIP_BLANKS; | 
 | 8582 | 	if (*type == NODE_TYPE_PI) { | 
 | 8583 | 	    /* | 
 | 8584 | 	     * Specific case: search a PI by name. | 
 | 8585 | 	     */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8586 | 	    if (name != NULL) | 
 | 8587 | 		xmlFree(name); | 
| Daniel Veillard | 82e4971 | 2001-04-26 14:38:03 +0000 | [diff] [blame] | 8588 | 	    name = NULL; | 
 | 8589 | 	    if (CUR != ')') { | 
 | 8590 | 		name = xmlXPathParseLiteral(ctxt); | 
 | 8591 | 		CHECK_ERROR 0; | 
| Daniel Veillard | ed23b7d | 2002-05-27 12:16:02 +0000 | [diff] [blame] | 8592 | 		*test = NODE_TEST_PI; | 
| Daniel Veillard | 82e4971 | 2001-04-26 14:38:03 +0000 | [diff] [blame] | 8593 | 		SKIP_BLANKS; | 
 | 8594 | 	    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8595 | 	} | 
 | 8596 | 	if (CUR != ')') { | 
 | 8597 | 	    if (name != NULL) | 
 | 8598 | 		xmlFree(name); | 
 | 8599 | 	    XP_ERROR0(XPATH_UNCLOSED_ERROR); | 
 | 8600 | 	} | 
 | 8601 | 	NEXT; | 
 | 8602 | 	return(name); | 
 | 8603 |     } | 
 | 8604 |     *test = NODE_TEST_NAME; | 
 | 8605 |     if ((!blanks) && (CUR == ':')) { | 
 | 8606 | 	NEXT; | 
 | 8607 |  | 
 | 8608 | 	/* | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 8609 | 	 * Since currently the parser context don't have a | 
 | 8610 | 	 * namespace list associated: | 
 | 8611 | 	 * The namespace name for this prefix can be computed | 
 | 8612 | 	 * only at evaluation time. The compilation is done | 
 | 8613 | 	 * outside of any context. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8614 | 	 */ | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 8615 | #if 0 | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8616 | 	*prefix = xmlXPathNsLookup(ctxt->context, name); | 
 | 8617 | 	if (name != NULL) | 
 | 8618 | 	    xmlFree(name); | 
 | 8619 | 	if (*prefix == NULL) { | 
 | 8620 | 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); | 
 | 8621 | 	} | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 8622 | #else | 
 | 8623 | 	*prefix = name; | 
 | 8624 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8625 |  | 
 | 8626 | 	if (CUR == '*') { | 
 | 8627 | 	    /* | 
 | 8628 | 	     * All elements | 
 | 8629 | 	     */ | 
 | 8630 | 	    NEXT; | 
 | 8631 | 	    *test = NODE_TEST_ALL; | 
 | 8632 | 	    return(NULL); | 
 | 8633 | 	} | 
 | 8634 |  | 
 | 8635 | 	name = xmlXPathParseNCName(ctxt); | 
 | 8636 | 	if (name == NULL) { | 
 | 8637 | 	    XP_ERROR0(XPATH_EXPR_ERROR); | 
 | 8638 | 	} | 
 | 8639 |     } | 
 | 8640 |     return(name); | 
 | 8641 | } | 
 | 8642 |  | 
 | 8643 | /** | 
 | 8644 |  * xmlXPathIsAxisName: | 
 | 8645 |  * @name:  a preparsed name token | 
 | 8646 |  * | 
 | 8647 |  * [6] AxisName ::=   'ancestor' | 
 | 8648 |  *                  | 'ancestor-or-self' | 
 | 8649 |  *                  | 'attribute' | 
 | 8650 |  *                  | 'child' | 
 | 8651 |  *                  | 'descendant' | 
 | 8652 |  *                  | 'descendant-or-self' | 
 | 8653 |  *                  | 'following' | 
 | 8654 |  *                  | 'following-sibling' | 
 | 8655 |  *                  | 'namespace' | 
 | 8656 |  *                  | 'parent' | 
 | 8657 |  *                  | 'preceding' | 
 | 8658 |  *                  | 'preceding-sibling' | 
 | 8659 |  *                  | 'self' | 
 | 8660 |  * | 
 | 8661 |  * Returns the axis or 0 | 
 | 8662 |  */ | 
| Daniel Veillard | 56a4cb8 | 2001-03-24 17:00:36 +0000 | [diff] [blame] | 8663 | static xmlXPathAxisVal | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8664 | xmlXPathIsAxisName(const xmlChar *name) { | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 8665 |     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8666 |     switch (name[0]) { | 
 | 8667 | 	case 'a': | 
 | 8668 | 	    if (xmlStrEqual(name, BAD_CAST "ancestor")) | 
 | 8669 | 		ret = AXIS_ANCESTOR; | 
 | 8670 | 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) | 
 | 8671 | 		ret = AXIS_ANCESTOR_OR_SELF; | 
 | 8672 | 	    if (xmlStrEqual(name, BAD_CAST "attribute")) | 
 | 8673 | 		ret = AXIS_ATTRIBUTE; | 
 | 8674 | 	    break; | 
 | 8675 | 	case 'c': | 
 | 8676 | 	    if (xmlStrEqual(name, BAD_CAST "child")) | 
 | 8677 | 		ret = AXIS_CHILD; | 
 | 8678 | 	    break; | 
 | 8679 | 	case 'd': | 
 | 8680 | 	    if (xmlStrEqual(name, BAD_CAST "descendant")) | 
 | 8681 | 		ret = AXIS_DESCENDANT; | 
 | 8682 | 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) | 
 | 8683 | 		ret = AXIS_DESCENDANT_OR_SELF; | 
 | 8684 | 	    break; | 
 | 8685 | 	case 'f': | 
 | 8686 | 	    if (xmlStrEqual(name, BAD_CAST "following")) | 
 | 8687 | 		ret = AXIS_FOLLOWING; | 
 | 8688 | 	    if (xmlStrEqual(name, BAD_CAST "following-sibling")) | 
 | 8689 | 		ret = AXIS_FOLLOWING_SIBLING; | 
 | 8690 | 	    break; | 
 | 8691 | 	case 'n': | 
 | 8692 | 	    if (xmlStrEqual(name, BAD_CAST "namespace")) | 
 | 8693 | 		ret = AXIS_NAMESPACE; | 
 | 8694 | 	    break; | 
 | 8695 | 	case 'p': | 
 | 8696 | 	    if (xmlStrEqual(name, BAD_CAST "parent")) | 
 | 8697 | 		ret = AXIS_PARENT; | 
 | 8698 | 	    if (xmlStrEqual(name, BAD_CAST "preceding")) | 
 | 8699 | 		ret = AXIS_PRECEDING; | 
 | 8700 | 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) | 
 | 8701 | 		ret = AXIS_PRECEDING_SIBLING; | 
 | 8702 | 	    break; | 
 | 8703 | 	case 's': | 
 | 8704 | 	    if (xmlStrEqual(name, BAD_CAST "self")) | 
 | 8705 | 		ret = AXIS_SELF; | 
 | 8706 | 	    break; | 
 | 8707 |     } | 
 | 8708 |     return(ret); | 
 | 8709 | } | 
 | 8710 |  | 
 | 8711 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8712 |  * xmlXPathCompStep: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8713 |  * @ctxt:  the XPath Parser context | 
 | 8714 |  * | 
 | 8715 |  * [4] Step ::=   AxisSpecifier NodeTest Predicate* | 
 | 8716 |  *                  | AbbreviatedStep  | 
 | 8717 |  * | 
 | 8718 |  * [12] AbbreviatedStep ::=   '.' | '..' | 
 | 8719 |  * | 
 | 8720 |  * [5] AxisSpecifier ::= AxisName '::' | 
 | 8721 |  *                  | AbbreviatedAxisSpecifier | 
 | 8722 |  * | 
 | 8723 |  * [13] AbbreviatedAxisSpecifier ::= '@'? | 
 | 8724 |  * | 
 | 8725 |  * Modified for XPtr range support as: | 
 | 8726 |  * | 
 | 8727 |  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate* | 
 | 8728 |  *                     | AbbreviatedStep | 
 | 8729 |  *                     | 'range-to' '(' Expr ')' Predicate* | 
 | 8730 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8731 |  * Compile one step in a Location Path | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8732 |  * A location step of . is short for self::node(). This is | 
 | 8733 |  * particularly useful in conjunction with //. For example, the | 
 | 8734 |  * location path .//para is short for | 
 | 8735 |  * self::node()/descendant-or-self::node()/child::para | 
 | 8736 |  * and so will select all para descendant elements of the context | 
 | 8737 |  * node. | 
 | 8738 |  * Similarly, a location step of .. is short for parent::node(). | 
 | 8739 |  * For example, ../title is short for parent::node()/child::title | 
 | 8740 |  * and so will select the title children of the parent of the context | 
 | 8741 |  * node. | 
 | 8742 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8743 | static void | 
 | 8744 | xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 8745 | #ifdef LIBXML_XPTR_ENABLED | 
 | 8746 |     int rangeto = 0; | 
 | 8747 |     int op2 = -1; | 
 | 8748 | #endif | 
 | 8749 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8750 |     SKIP_BLANKS; | 
 | 8751 |     if ((CUR == '.') && (NXT(1) == '.')) { | 
 | 8752 | 	SKIP(2); | 
 | 8753 | 	SKIP_BLANKS; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8754 | 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, | 
 | 8755 | 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8756 |     } else if (CUR == '.') { | 
 | 8757 | 	NEXT; | 
 | 8758 | 	SKIP_BLANKS; | 
 | 8759 |     } else { | 
 | 8760 | 	xmlChar *name = NULL; | 
 | 8761 | 	const xmlChar *prefix = NULL; | 
 | 8762 | 	xmlXPathTestVal test; | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 8763 | 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8764 | 	xmlXPathTypeVal type; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8765 | 	int op1; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8766 |  | 
 | 8767 | 	/* | 
 | 8768 | 	 * The modification needed for XPointer change to the production | 
 | 8769 | 	 */ | 
 | 8770 | #ifdef LIBXML_XPTR_ENABLED | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 8771 | 	if (ctxt->xptr) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8772 | 	    name = xmlXPathParseNCName(ctxt); | 
 | 8773 | 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 8774 |                 op2 = ctxt->comp->last; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8775 | 		xmlFree(name); | 
 | 8776 | 		SKIP_BLANKS; | 
 | 8777 | 		if (CUR != '(') { | 
 | 8778 | 		    XP_ERROR(XPATH_EXPR_ERROR); | 
 | 8779 | 		} | 
 | 8780 | 		NEXT; | 
 | 8781 | 		SKIP_BLANKS; | 
 | 8782 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8783 | 		xmlXPathCompileExpr(ctxt); | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 8784 | 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8785 | 		CHECK_ERROR; | 
 | 8786 |  | 
 | 8787 | 		SKIP_BLANKS; | 
 | 8788 | 		if (CUR != ')') { | 
 | 8789 | 		    XP_ERROR(XPATH_EXPR_ERROR); | 
 | 8790 | 		} | 
 | 8791 | 		NEXT; | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 8792 | 		rangeto = 1; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8793 | 		goto eval_predicates; | 
 | 8794 | 	    } | 
 | 8795 | 	} | 
 | 8796 | #endif | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 8797 | 	if (CUR == '*') { | 
 | 8798 | 	    axis = AXIS_CHILD; | 
 | 8799 | 	} else { | 
 | 8800 | 	    if (name == NULL) | 
 | 8801 | 		name = xmlXPathParseNCName(ctxt); | 
 | 8802 | 	    if (name != NULL) { | 
 | 8803 | 		axis = xmlXPathIsAxisName(name); | 
 | 8804 | 		if (axis != 0) { | 
 | 8805 | 		    SKIP_BLANKS; | 
 | 8806 | 		    if ((CUR == ':') && (NXT(1) == ':')) { | 
 | 8807 | 			SKIP(2); | 
 | 8808 | 			xmlFree(name); | 
 | 8809 | 			name = NULL; | 
 | 8810 | 		    } else { | 
 | 8811 | 			/* an element name can conflict with an axis one :-\ */ | 
 | 8812 | 			axis = AXIS_CHILD; | 
 | 8813 | 		    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8814 | 		} else { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8815 | 		    axis = AXIS_CHILD; | 
 | 8816 | 		} | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 8817 | 	    } else if (CUR == '@') { | 
 | 8818 | 		NEXT; | 
 | 8819 | 		axis = AXIS_ATTRIBUTE; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8820 | 	    } else { | 
| Daniel Veillard | 2156a56 | 2001-04-28 12:24:34 +0000 | [diff] [blame] | 8821 | 		axis = AXIS_CHILD; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8822 | 	    } | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8823 | 	} | 
 | 8824 |  | 
 | 8825 | 	CHECK_ERROR; | 
 | 8826 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8827 | 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8828 | 	if (test == 0) | 
 | 8829 | 	    return; | 
 | 8830 |  | 
 | 8831 | #ifdef DEBUG_STEP | 
 | 8832 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 8833 | 		"Basis : computing new set\n"); | 
 | 8834 | #endif | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8835 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8836 | #ifdef DEBUG_STEP | 
 | 8837 | 	xmlGenericError(xmlGenericErrorContext, "Basis : "); | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 8838 | 	if (ctxt->value == NULL) | 
 | 8839 | 	    xmlGenericError(xmlGenericErrorContext, "no value\n"); | 
 | 8840 | 	else if (ctxt->value->nodesetval == NULL) | 
 | 8841 | 	    xmlGenericError(xmlGenericErrorContext, "Empty\n"); | 
 | 8842 | 	else | 
 | 8843 | 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8844 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8845 |  | 
| Daniel Veillard | 5bb9ccd | 2004-02-09 12:39:02 +0000 | [diff] [blame] | 8846 | #ifdef LIBXML_XPTR_ENABLED | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8847 | eval_predicates: | 
| Daniel Veillard | 5bb9ccd | 2004-02-09 12:39:02 +0000 | [diff] [blame] | 8848 | #endif | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8849 | 	op1 = ctxt->comp->last; | 
 | 8850 | 	ctxt->comp->last = -1; | 
 | 8851 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8852 | 	SKIP_BLANKS; | 
 | 8853 | 	while (CUR == '[') { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8854 | 	    xmlXPathCompPredicate(ctxt, 0); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8855 | 	} | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8856 |  | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 8857 | #ifdef LIBXML_XPTR_ENABLED | 
 | 8858 | 	if (rangeto) { | 
 | 8859 | 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); | 
 | 8860 | 	} else | 
 | 8861 | #endif | 
 | 8862 | 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, | 
 | 8863 | 			   test, type, (void *)prefix, (void *)name); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8864 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8865 |     } | 
 | 8866 | #ifdef DEBUG_STEP | 
 | 8867 |     xmlGenericError(xmlGenericErrorContext, "Step : "); | 
| Daniel Veillard | fd0c3eb | 2001-04-22 19:13:10 +0000 | [diff] [blame] | 8868 |     if (ctxt->value == NULL) | 
 | 8869 | 	xmlGenericError(xmlGenericErrorContext, "no value\n"); | 
 | 8870 |     else if (ctxt->value->nodesetval == NULL) | 
 | 8871 | 	xmlGenericError(xmlGenericErrorContext, "Empty\n"); | 
 | 8872 |     else | 
 | 8873 | 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext, | 
 | 8874 | 		ctxt->value->nodesetval); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8875 | #endif | 
 | 8876 | } | 
 | 8877 |  | 
 | 8878 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8879 |  * xmlXPathCompRelativeLocationPath: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8880 |  * @ctxt:  the XPath Parser context | 
 | 8881 |  * | 
 | 8882 |  *  [3]   RelativeLocationPath ::=   Step  | 
 | 8883 |  *                     | RelativeLocationPath '/' Step  | 
 | 8884 |  *                     | AbbreviatedRelativeLocationPath  | 
 | 8885 |  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step  | 
 | 8886 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8887 |  * Compile a relative location path. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8888 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8889 | static void | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8890 | xmlXPathCompRelativeLocationPath | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8891 | (xmlXPathParserContextPtr ctxt) { | 
 | 8892 |     SKIP_BLANKS; | 
 | 8893 |     if ((CUR == '/') && (NXT(1) == '/')) { | 
 | 8894 | 	SKIP(2); | 
 | 8895 | 	SKIP_BLANKS; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8896 | 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, | 
 | 8897 | 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8898 |     } else if (CUR == '/') { | 
 | 8899 | 	    NEXT; | 
 | 8900 | 	SKIP_BLANKS; | 
 | 8901 |     } | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8902 |     xmlXPathCompStep(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8903 |     SKIP_BLANKS; | 
 | 8904 |     while (CUR == '/') { | 
 | 8905 | 	if ((CUR == '/') && (NXT(1) == '/')) { | 
 | 8906 | 	    SKIP(2); | 
 | 8907 | 	    SKIP_BLANKS; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8908 | 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8909 | 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8910 | 	    xmlXPathCompStep(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8911 | 	} else if (CUR == '/') { | 
 | 8912 | 	    NEXT; | 
 | 8913 | 	    SKIP_BLANKS; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8914 | 	    xmlXPathCompStep(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8915 | 	} | 
 | 8916 | 	SKIP_BLANKS; | 
 | 8917 |     } | 
 | 8918 | } | 
 | 8919 |  | 
 | 8920 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8921 |  * xmlXPathCompLocationPath: | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8922 |  * @ctxt:  the XPath Parser context | 
 | 8923 |  * | 
 | 8924 |  *  [1]   LocationPath ::=   RelativeLocationPath  | 
 | 8925 |  *                     | AbsoluteLocationPath  | 
 | 8926 |  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath? | 
 | 8927 |  *                     | AbbreviatedAbsoluteLocationPath  | 
 | 8928 |  *  [10]   AbbreviatedAbsoluteLocationPath ::=    | 
 | 8929 |  *                           '//' RelativeLocationPath  | 
 | 8930 |  * | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8931 |  * Compile a location path | 
 | 8932 |  * | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8933 |  * // is short for /descendant-or-self::node()/. For example, | 
 | 8934 |  * //para is short for /descendant-or-self::node()/child::para and | 
 | 8935 |  * so will select any para element in the document (even a para element | 
 | 8936 |  * that is a document element will be selected by //para since the | 
 | 8937 |  * document element node is a child of the root node); div//para is | 
 | 8938 |  * short for div/descendant-or-self::node()/child::para and so will | 
 | 8939 |  * select all para descendants of div children. | 
 | 8940 |  */ | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8941 | static void | 
 | 8942 | xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8943 |     SKIP_BLANKS; | 
 | 8944 |     if (CUR != '/') { | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8945 |         xmlXPathCompRelativeLocationPath(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8946 |     } else { | 
 | 8947 | 	while (CUR == '/') { | 
 | 8948 | 	    if ((CUR == '/') && (NXT(1) == '/')) { | 
 | 8949 | 		SKIP(2); | 
 | 8950 | 		SKIP_BLANKS; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8951 | 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, | 
 | 8952 | 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8953 | 		xmlXPathCompRelativeLocationPath(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8954 | 	    } else if (CUR == '/') { | 
 | 8955 | 		NEXT; | 
| Daniel Veillard | 608ad07 | 2001-06-14 08:32:28 +0000 | [diff] [blame] | 8956 | 		SKIP_BLANKS; | 
 | 8957 | 		if ((CUR != 0 ) && | 
| William M. Brack | d1757ab | 2004-10-02 22:07:48 +0000 | [diff] [blame] | 8958 | 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || | 
| Daniel Veillard | 608ad07 | 2001-06-14 08:32:28 +0000 | [diff] [blame] | 8959 | 		     (CUR == '@') || (CUR == '*'))) | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 8960 | 		    xmlXPathCompRelativeLocationPath(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 8961 | 	    } | 
 | 8962 | 	} | 
 | 8963 |     } | 
 | 8964 | } | 
 | 8965 |  | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 8966 | /************************************************************************ | 
 | 8967 |  *									* | 
 | 8968 |  * 		XPath precompiled expression evaluation			* | 
 | 8969 |  *									* | 
 | 8970 |  ************************************************************************/ | 
 | 8971 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 8972 | static int | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8973 | xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); | 
 | 8974 |  | 
 | 8975 | /** | 
 | 8976 |  * xmlXPathNodeCollectAndTest: | 
 | 8977 |  * @ctxt:  the XPath Parser context | 
 | 8978 |  * @op:  the XPath precompiled step operation | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 8979 |  * @first:  pointer to the first element in document order | 
 | 8980 |  * @last:  pointer to the last element in document order | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8981 |  * | 
 | 8982 |  * This is the function implementing a step: based on the current list | 
 | 8983 |  * of nodes, it builds up a new list, looking at all nodes under that | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 8984 |  * axis and selecting them. It also does the predicate filtering | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8985 |  * | 
 | 8986 |  * Pushes the new NodeSet resulting from the search. | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 8987 |  * | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 8988 |  * Returns the number of nodes traversed | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8989 |  */ | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 8990 | static int | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8991 | xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 8992 |                            xmlXPathStepOpPtr op, | 
 | 8993 | 			   xmlNodePtr * first, xmlNodePtr * last) | 
 | 8994 | { | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 8995 |     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; | 
 | 8996 |     xmlXPathTestVal test = (xmlXPathTestVal) op->value2; | 
 | 8997 |     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 8998 |     const xmlChar *prefix = op->value4; | 
 | 8999 |     const xmlChar *name = op->value5; | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 9000 |     const xmlChar *URI = NULL; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9001 |  | 
 | 9002 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9003 |     int n = 0; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9004 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9005 |     int i, t = 0; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9006 |     xmlNodeSetPtr ret, list; | 
 | 9007 |     xmlXPathTraversalFunction next = NULL; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9008 |     void (*addNode) (xmlNodeSetPtr, xmlNodePtr); | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 9009 |     xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9010 |     xmlNodePtr cur = NULL; | 
 | 9011 |     xmlXPathObjectPtr obj; | 
 | 9012 |     xmlNodeSetPtr nodelist; | 
 | 9013 |     xmlNodePtr tmp; | 
 | 9014 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9015 |     CHECK_TYPE0(XPATH_NODESET); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9016 |     obj = valuePop(ctxt); | 
 | 9017 |     addNode = xmlXPathNodeSetAdd; | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 9018 |     mergeNodeSet = xmlXPathNodeSetMerge; | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 9019 |     if (prefix != NULL) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9020 |         URI = xmlXPathNsLookup(ctxt->context, prefix); | 
 | 9021 |         if (URI == NULL) | 
 | 9022 |             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); | 
| Daniel Veillard | e043ee1 | 2001-04-16 14:08:07 +0000 | [diff] [blame] | 9023 |     } | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9024 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9025 |     xmlGenericError(xmlGenericErrorContext, "new step : "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9026 | #endif | 
 | 9027 |     switch (axis) { | 
 | 9028 |         case AXIS_ANCESTOR: | 
 | 9029 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9030 |             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9031 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9032 |             first = NULL; | 
 | 9033 |             next = xmlXPathNextAncestor; | 
 | 9034 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9035 |         case AXIS_ANCESTOR_OR_SELF: | 
 | 9036 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9037 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9038 |                             "axis 'ancestors-or-self' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9039 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9040 |             first = NULL; | 
 | 9041 |             next = xmlXPathNextAncestorOrSelf; | 
 | 9042 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9043 |         case AXIS_ATTRIBUTE: | 
 | 9044 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9045 |             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9046 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9047 |             first = NULL; | 
 | 9048 | 	    last = NULL; | 
 | 9049 |             next = xmlXPathNextAttribute; | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 9050 | 	    mergeNodeSet = xmlXPathNodeSetMergeUnique; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9051 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9052 |         case AXIS_CHILD: | 
 | 9053 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9054 |             xmlGenericError(xmlGenericErrorContext, "axis 'child' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9055 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9056 | 	    last = NULL; | 
 | 9057 |             next = xmlXPathNextChild; | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 9058 | 	    mergeNodeSet = xmlXPathNodeSetMergeUnique; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9059 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9060 |         case AXIS_DESCENDANT: | 
 | 9061 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9062 |             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9063 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9064 | 	    last = NULL; | 
 | 9065 |             next = xmlXPathNextDescendant; | 
 | 9066 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9067 |         case AXIS_DESCENDANT_OR_SELF: | 
 | 9068 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9069 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9070 |                             "axis 'descendant-or-self' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9071 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9072 | 	    last = NULL; | 
 | 9073 |             next = xmlXPathNextDescendantOrSelf; | 
 | 9074 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9075 |         case AXIS_FOLLOWING: | 
 | 9076 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9077 |             xmlGenericError(xmlGenericErrorContext, "axis 'following' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9078 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9079 | 	    last = NULL; | 
 | 9080 |             next = xmlXPathNextFollowing; | 
 | 9081 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9082 |         case AXIS_FOLLOWING_SIBLING: | 
 | 9083 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9084 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9085 |                             "axis 'following-siblings' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9086 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9087 | 	    last = NULL; | 
 | 9088 |             next = xmlXPathNextFollowingSibling; | 
 | 9089 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9090 |         case AXIS_NAMESPACE: | 
 | 9091 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9092 |             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9093 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9094 |             first = NULL; | 
 | 9095 | 	    last = NULL; | 
 | 9096 |             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 9097 | 	    mergeNodeSet = xmlXPathNodeSetMergeUnique; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9098 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9099 |         case AXIS_PARENT: | 
 | 9100 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9101 |             xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9102 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9103 |             first = NULL; | 
 | 9104 |             next = xmlXPathNextParent; | 
 | 9105 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9106 |         case AXIS_PRECEDING: | 
 | 9107 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9108 |             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9109 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9110 |             first = NULL; | 
 | 9111 |             next = xmlXPathNextPrecedingInternal; | 
 | 9112 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9113 |         case AXIS_PRECEDING_SIBLING: | 
 | 9114 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9115 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9116 |                             "axis 'preceding-sibling' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9117 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9118 |             first = NULL; | 
 | 9119 |             next = xmlXPathNextPrecedingSibling; | 
 | 9120 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9121 |         case AXIS_SELF: | 
 | 9122 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9123 |             xmlGenericError(xmlGenericErrorContext, "axis 'self' "); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9124 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9125 |             first = NULL; | 
 | 9126 | 	    last = NULL; | 
 | 9127 |             next = xmlXPathNextSelf; | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 9128 | 	    mergeNodeSet = xmlXPathNodeSetMergeUnique; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9129 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9130 |     } | 
 | 9131 |     if (next == NULL) | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9132 |         return(0); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9133 |  | 
 | 9134 |     nodelist = obj->nodesetval; | 
 | 9135 |     if (nodelist == NULL) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9136 |         xmlXPathFreeObject(obj); | 
 | 9137 |         valuePush(ctxt, xmlXPathWrapNodeSet(NULL)); | 
 | 9138 |         return(0); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9139 |     } | 
 | 9140 |     addNode = xmlXPathNodeSetAddUnique; | 
 | 9141 |     ret = NULL; | 
 | 9142 | #ifdef DEBUG_STEP | 
 | 9143 |     xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9144 |                     " context contains %d nodes\n", nodelist->nodeNr); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9145 |     switch (test) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9146 |         case NODE_TEST_NONE: | 
 | 9147 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9148 |                             "           searching for none !!!\n"); | 
 | 9149 |             break; | 
 | 9150 |         case NODE_TEST_TYPE: | 
 | 9151 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9152 |                             "           searching for type %d\n", type); | 
 | 9153 |             break; | 
 | 9154 |         case NODE_TEST_PI: | 
 | 9155 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9156 |                             "           searching for PI !!!\n"); | 
 | 9157 |             break; | 
 | 9158 |         case NODE_TEST_ALL: | 
 | 9159 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9160 |                             "           searching for *\n"); | 
 | 9161 |             break; | 
 | 9162 |         case NODE_TEST_NS: | 
 | 9163 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9164 |                             "           searching for namespace %s\n", | 
 | 9165 |                             prefix); | 
 | 9166 |             break; | 
 | 9167 |         case NODE_TEST_NAME: | 
 | 9168 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9169 |                             "           searching for name %s\n", name); | 
 | 9170 |             if (prefix != NULL) | 
 | 9171 |                 xmlGenericError(xmlGenericErrorContext, | 
 | 9172 |                                 "           with namespace %s\n", prefix); | 
 | 9173 |             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9174 |     } | 
 | 9175 |     xmlGenericError(xmlGenericErrorContext, "Testing : "); | 
 | 9176 | #endif | 
 | 9177 |     /* | 
 | 9178 |      * 2.3 Node Tests | 
 | 9179 |      *  - For the attribute axis, the principal node type is attribute.  | 
 | 9180 |      *  - For the namespace axis, the principal node type is namespace.  | 
 | 9181 |      *  - For other axes, the principal node type is element.  | 
 | 9182 |      * | 
 | 9183 |      * A node test * is true for any node of the | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 9184 |      * principal node type. For example, child::* will | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9185 |      * select all element children of the context node | 
 | 9186 |      */ | 
 | 9187 |     tmp = ctxt->context->node; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9188 |     for (i = 0; i < nodelist->nodeNr; i++) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9189 |         ctxt->context->node = nodelist->nodeTab[i]; | 
 | 9190 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9191 |         cur = NULL; | 
 | 9192 |         list = xmlXPathNodeSetCreate(NULL); | 
 | 9193 |         do { | 
 | 9194 |             cur = next(ctxt, cur); | 
 | 9195 |             if (cur == NULL) | 
 | 9196 |                 break; | 
 | 9197 |             if ((first != NULL) && (*first == cur)) | 
 | 9198 |                 break; | 
 | 9199 | 	    if (((t % 256) == 0) && | 
 | 9200 | 	        (first != NULL) && (*first != NULL) && | 
 | 9201 | 		(xmlXPathCmpNodes(*first, cur) >= 0)) | 
 | 9202 | 		break; | 
 | 9203 | 	    if ((last != NULL) && (*last == cur)) | 
 | 9204 | 		break; | 
 | 9205 | 	    if (((t % 256) == 0) && | 
 | 9206 | 		(last != NULL) && (*last != NULL) && | 
 | 9207 | 		(xmlXPathCmpNodes(cur, *last) >= 0)) | 
 | 9208 | 		break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9209 |             t++; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9210 | #ifdef DEBUG_STEP | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9211 |             xmlGenericError(xmlGenericErrorContext, " %s", cur->name); | 
 | 9212 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9213 |             switch (test) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9214 |                 case NODE_TEST_NONE: | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9215 |                     ctxt->context->node = tmp; | 
 | 9216 |                     STRANGE return(t); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9217 |                 case NODE_TEST_TYPE: | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9218 |                     if ((cur->type == type) || | 
 | 9219 |                         ((type == NODE_TYPE_NODE) && | 
 | 9220 |                          ((cur->type == XML_DOCUMENT_NODE) || | 
 | 9221 |                           (cur->type == XML_HTML_DOCUMENT_NODE) || | 
 | 9222 |                           (cur->type == XML_ELEMENT_NODE) || | 
| Aleksey Sanin | f8cb6dd | 2002-06-04 04:27:06 +0000 | [diff] [blame] | 9223 |                           (cur->type == XML_NAMESPACE_DECL) || | 
 | 9224 |                           (cur->type == XML_ATTRIBUTE_NODE) || | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9225 |                           (cur->type == XML_PI_NODE) || | 
 | 9226 |                           (cur->type == XML_COMMENT_NODE) || | 
 | 9227 |                           (cur->type == XML_CDATA_SECTION_NODE) || | 
| Daniel Veillard | 7583a59 | 2001-07-08 13:15:55 +0000 | [diff] [blame] | 9228 |                           (cur->type == XML_TEXT_NODE))) || | 
 | 9229 | 			((type == NODE_TYPE_TEXT) && | 
 | 9230 | 			 (cur->type == XML_CDATA_SECTION_NODE))) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9231 | #ifdef DEBUG_STEP | 
 | 9232 |                         n++; | 
 | 9233 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9234 |                         addNode(list, cur); | 
 | 9235 |                     } | 
 | 9236 |                     break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9237 |                 case NODE_TEST_PI: | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9238 |                     if (cur->type == XML_PI_NODE) { | 
 | 9239 |                         if ((name != NULL) && | 
 | 9240 |                             (!xmlStrEqual(name, cur->name))) | 
 | 9241 |                             break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9242 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9243 |                         n++; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9244 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9245 |                         addNode(list, cur); | 
 | 9246 |                     } | 
 | 9247 |                     break; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9248 |                 case NODE_TEST_ALL: | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9249 |                     if (axis == AXIS_ATTRIBUTE) { | 
 | 9250 |                         if (cur->type == XML_ATTRIBUTE_NODE) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9251 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9252 |                             n++; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9253 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9254 |                             addNode(list, cur); | 
 | 9255 |                         } | 
 | 9256 |                     } else if (axis == AXIS_NAMESPACE) { | 
 | 9257 |                         if (cur->type == XML_NAMESPACE_DECL) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9258 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9259 |                             n++; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9260 | #endif | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 9261 |                             xmlXPathNodeSetAddNs(list, ctxt->context->node,  | 
 | 9262 | 				                 (xmlNsPtr) cur); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9263 |                         } | 
 | 9264 |                     } else { | 
 | 9265 |                         if (cur->type == XML_ELEMENT_NODE) { | 
 | 9266 |                             if (prefix == NULL) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9267 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9268 |                                 n++; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9269 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9270 |                                 addNode(list, cur); | 
 | 9271 |                             } else if ((cur->ns != NULL) && | 
 | 9272 |                                        (xmlStrEqual(URI, cur->ns->href))) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9273 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9274 |                                 n++; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9275 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9276 |                                 addNode(list, cur); | 
 | 9277 |                             } | 
 | 9278 |                         } | 
 | 9279 |                     } | 
 | 9280 |                     break; | 
 | 9281 |                 case NODE_TEST_NS:{ | 
 | 9282 |                         TODO; | 
 | 9283 |                         break; | 
 | 9284 |                     } | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9285 |                 case NODE_TEST_NAME: | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9286 |                     switch (cur->type) { | 
 | 9287 |                         case XML_ELEMENT_NODE: | 
 | 9288 |                             if (xmlStrEqual(name, cur->name)) { | 
 | 9289 |                                 if (prefix == NULL) { | 
 | 9290 |                                     if (cur->ns == NULL) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9291 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9292 |                                         n++; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9293 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9294 |                                         addNode(list, cur); | 
 | 9295 |                                     } | 
 | 9296 |                                 } else { | 
 | 9297 |                                     if ((cur->ns != NULL) && | 
 | 9298 |                                         (xmlStrEqual(URI, | 
 | 9299 |                                                      cur->ns->href))) { | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9300 | #ifdef DEBUG_STEP | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9301 |                                         n++; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9302 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9303 |                                         addNode(list, cur); | 
 | 9304 |                                     } | 
 | 9305 |                                 } | 
 | 9306 |                             } | 
 | 9307 |                             break; | 
 | 9308 |                         case XML_ATTRIBUTE_NODE:{ | 
 | 9309 |                                 xmlAttrPtr attr = (xmlAttrPtr) cur; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9310 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9311 |                                 if (xmlStrEqual(name, attr->name)) { | 
 | 9312 |                                     if (prefix == NULL) { | 
 | 9313 |                                         if ((attr->ns == NULL) || | 
 | 9314 |                                             (attr->ns->prefix == NULL)) { | 
 | 9315 | #ifdef DEBUG_STEP | 
 | 9316 |                                             n++; | 
 | 9317 | #endif | 
 | 9318 |                                             addNode(list, | 
 | 9319 |                                                     (xmlNodePtr) attr); | 
 | 9320 |                                         } | 
 | 9321 |                                     } else { | 
 | 9322 |                                         if ((attr->ns != NULL) && | 
 | 9323 |                                             (xmlStrEqual(URI, | 
 | 9324 |                                                          attr->ns-> | 
 | 9325 |                                                          href))) { | 
 | 9326 | #ifdef DEBUG_STEP | 
 | 9327 |                                             n++; | 
 | 9328 | #endif | 
 | 9329 |                                             addNode(list, | 
 | 9330 |                                                     (xmlNodePtr) attr); | 
 | 9331 |                                         } | 
 | 9332 |                                     } | 
 | 9333 |                                 } | 
 | 9334 |                                 break; | 
 | 9335 |                             } | 
 | 9336 |                         case XML_NAMESPACE_DECL: | 
 | 9337 |                             if (cur->type == XML_NAMESPACE_DECL) { | 
 | 9338 |                                 xmlNsPtr ns = (xmlNsPtr) cur; | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9339 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9340 |                                 if ((ns->prefix != NULL) && (name != NULL) | 
 | 9341 |                                     && (xmlStrEqual(ns->prefix, name))) { | 
 | 9342 | #ifdef DEBUG_STEP | 
 | 9343 |                                     n++; | 
 | 9344 | #endif | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 9345 | 				    xmlXPathNodeSetAddNs(list, | 
 | 9346 | 					ctxt->context->node, (xmlNsPtr) cur); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9347 |                                 } | 
 | 9348 |                             } | 
 | 9349 |                             break; | 
 | 9350 |                         default: | 
 | 9351 |                             break; | 
 | 9352 |                     } | 
 | 9353 |                     break; | 
 | 9354 |                     break; | 
 | 9355 |             } | 
 | 9356 |         } while (cur != NULL); | 
 | 9357 |  | 
 | 9358 |         /* | 
 | 9359 |          * If there is some predicate filtering do it now | 
 | 9360 |          */ | 
| Daniel Veillard | 6fbcf42 | 2002-03-21 12:32:59 +0000 | [diff] [blame] | 9361 |         if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9362 |             xmlXPathObjectPtr obj2; | 
 | 9363 |  | 
 | 9364 |             valuePush(ctxt, xmlXPathWrapNodeSet(list)); | 
 | 9365 |             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]); | 
 | 9366 |             CHECK_TYPE0(XPATH_NODESET); | 
 | 9367 |             obj2 = valuePop(ctxt); | 
 | 9368 |             list = obj2->nodesetval; | 
 | 9369 |             obj2->nodesetval = NULL; | 
 | 9370 |             xmlXPathFreeObject(obj2); | 
 | 9371 |         } | 
 | 9372 |         if (ret == NULL) { | 
 | 9373 |             ret = list; | 
 | 9374 |         } else { | 
| Daniel Veillard | 75be013 | 2002-03-13 10:03:35 +0000 | [diff] [blame] | 9375 |             ret = mergeNodeSet(ret, list); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9376 |             xmlXPathFreeNodeSet(list); | 
 | 9377 |         } | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9378 |     } | 
 | 9379 |     ctxt->context->node = tmp; | 
 | 9380 | #ifdef DEBUG_STEP | 
 | 9381 |     xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9382 |                     "\nExamined %d nodes, found %d nodes at that step\n", | 
 | 9383 |                     t, n); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9384 | #endif | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 9385 |     valuePush(ctxt, xmlXPathWrapNodeSet(ret)); | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 9386 |     if ((obj->boolval) && (obj->user != NULL)) { | 
 | 9387 | 	ctxt->value->boolval = 1; | 
 | 9388 | 	ctxt->value->user = obj->user; | 
 | 9389 | 	obj->user = NULL; | 
 | 9390 | 	obj->boolval = 0; | 
 | 9391 |     } | 
 | 9392 |     xmlXPathFreeObject(obj); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9393 |     return(t); | 
 | 9394 | } | 
 | 9395 |  | 
 | 9396 | /** | 
 | 9397 |  * xmlXPathNodeCollectAndTestNth: | 
 | 9398 |  * @ctxt:  the XPath Parser context | 
 | 9399 |  * @op:  the XPath precompiled step operation | 
 | 9400 |  * @indx:  the index to collect | 
 | 9401 |  * @first:  pointer to the first element in document order | 
 | 9402 |  * @last:  pointer to the last element in document order | 
 | 9403 |  * | 
 | 9404 |  * This is the function implementing a step: based on the current list | 
 | 9405 |  * of nodes, it builds up a new list, looking at all nodes under that | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 9406 |  * axis and selecting them. It also does the predicate filtering | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9407 |  * | 
 | 9408 |  * Pushes the new NodeSet resulting from the search. | 
 | 9409 |  * Returns the number of node traversed | 
 | 9410 |  */ | 
 | 9411 | static int | 
 | 9412 | xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt, | 
 | 9413 |                               xmlXPathStepOpPtr op, int indx, | 
 | 9414 |                               xmlNodePtr * first, xmlNodePtr * last) | 
 | 9415 | { | 
| William M. Brack | 78637da | 2003-07-31 14:47:38 +0000 | [diff] [blame] | 9416 |     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; | 
 | 9417 |     xmlXPathTestVal test = (xmlXPathTestVal) op->value2; | 
 | 9418 |     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9419 |     const xmlChar *prefix = op->value4; | 
 | 9420 |     const xmlChar *name = op->value5; | 
 | 9421 |     const xmlChar *URI = NULL; | 
 | 9422 |     int n = 0, t = 0; | 
 | 9423 |  | 
 | 9424 |     int i; | 
 | 9425 |     xmlNodeSetPtr list; | 
 | 9426 |     xmlXPathTraversalFunction next = NULL; | 
 | 9427 |     void (*addNode) (xmlNodeSetPtr, xmlNodePtr); | 
 | 9428 |     xmlNodePtr cur = NULL; | 
 | 9429 |     xmlXPathObjectPtr obj; | 
 | 9430 |     xmlNodeSetPtr nodelist; | 
 | 9431 |     xmlNodePtr tmp; | 
 | 9432 |  | 
 | 9433 |     CHECK_TYPE0(XPATH_NODESET); | 
 | 9434 |     obj = valuePop(ctxt); | 
 | 9435 |     addNode = xmlXPathNodeSetAdd; | 
 | 9436 |     if (prefix != NULL) { | 
 | 9437 |         URI = xmlXPathNsLookup(ctxt->context, prefix); | 
 | 9438 |         if (URI == NULL) | 
 | 9439 |             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); | 
 | 9440 |     } | 
 | 9441 | #ifdef DEBUG_STEP_NTH | 
 | 9442 |     xmlGenericError(xmlGenericErrorContext, "new step : "); | 
 | 9443 |     if (first != NULL) { | 
 | 9444 | 	if (*first != NULL) | 
 | 9445 | 	    xmlGenericError(xmlGenericErrorContext, "first = %s ", | 
 | 9446 | 		    (*first)->name); | 
 | 9447 | 	else | 
 | 9448 | 	    xmlGenericError(xmlGenericErrorContext, "first = NULL "); | 
 | 9449 |     } | 
 | 9450 |     if (last != NULL) { | 
 | 9451 | 	if (*last != NULL) | 
 | 9452 | 	    xmlGenericError(xmlGenericErrorContext, "last = %s ", | 
 | 9453 | 		    (*last)->name); | 
 | 9454 | 	else | 
 | 9455 | 	    xmlGenericError(xmlGenericErrorContext, "last = NULL "); | 
 | 9456 |     } | 
 | 9457 | #endif | 
 | 9458 |     switch (axis) { | 
 | 9459 |         case AXIS_ANCESTOR: | 
 | 9460 | #ifdef DEBUG_STEP_NTH | 
 | 9461 |             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); | 
 | 9462 | #endif | 
 | 9463 |             first = NULL; | 
 | 9464 |             next = xmlXPathNextAncestor; | 
 | 9465 |             break; | 
 | 9466 |         case AXIS_ANCESTOR_OR_SELF: | 
 | 9467 | #ifdef DEBUG_STEP_NTH | 
 | 9468 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9469 |                             "axis 'ancestors-or-self' "); | 
 | 9470 | #endif | 
 | 9471 |             first = NULL; | 
 | 9472 |             next = xmlXPathNextAncestorOrSelf; | 
 | 9473 |             break; | 
 | 9474 |         case AXIS_ATTRIBUTE: | 
 | 9475 | #ifdef DEBUG_STEP_NTH | 
 | 9476 |             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); | 
 | 9477 | #endif | 
 | 9478 |             first = NULL; | 
 | 9479 | 	    last = NULL; | 
 | 9480 |             next = xmlXPathNextAttribute; | 
 | 9481 |             break; | 
 | 9482 |         case AXIS_CHILD: | 
 | 9483 | #ifdef DEBUG_STEP_NTH | 
 | 9484 |             xmlGenericError(xmlGenericErrorContext, "axis 'child' "); | 
 | 9485 | #endif | 
 | 9486 | 	    last = NULL; | 
 | 9487 |             next = xmlXPathNextChild; | 
 | 9488 |             break; | 
 | 9489 |         case AXIS_DESCENDANT: | 
 | 9490 | #ifdef DEBUG_STEP_NTH | 
 | 9491 |             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); | 
 | 9492 | #endif | 
 | 9493 | 	    last = NULL; | 
 | 9494 |             next = xmlXPathNextDescendant; | 
 | 9495 |             break; | 
 | 9496 |         case AXIS_DESCENDANT_OR_SELF: | 
 | 9497 | #ifdef DEBUG_STEP_NTH | 
 | 9498 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9499 |                             "axis 'descendant-or-self' "); | 
 | 9500 | #endif | 
 | 9501 | 	    last = NULL; | 
 | 9502 |             next = xmlXPathNextDescendantOrSelf; | 
 | 9503 |             break; | 
 | 9504 |         case AXIS_FOLLOWING: | 
 | 9505 | #ifdef DEBUG_STEP_NTH | 
 | 9506 |             xmlGenericError(xmlGenericErrorContext, "axis 'following' "); | 
 | 9507 | #endif | 
 | 9508 | 	    last = NULL; | 
 | 9509 |             next = xmlXPathNextFollowing; | 
 | 9510 |             break; | 
 | 9511 |         case AXIS_FOLLOWING_SIBLING: | 
 | 9512 | #ifdef DEBUG_STEP_NTH | 
 | 9513 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9514 |                             "axis 'following-siblings' "); | 
 | 9515 | #endif | 
 | 9516 | 	    last = NULL; | 
 | 9517 |             next = xmlXPathNextFollowingSibling; | 
 | 9518 |             break; | 
 | 9519 |         case AXIS_NAMESPACE: | 
 | 9520 | #ifdef DEBUG_STEP_NTH | 
 | 9521 |             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); | 
 | 9522 | #endif | 
 | 9523 | 	    last = NULL; | 
 | 9524 |             first = NULL; | 
 | 9525 |             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; | 
 | 9526 |             break; | 
 | 9527 |         case AXIS_PARENT: | 
 | 9528 | #ifdef DEBUG_STEP_NTH | 
 | 9529 |             xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); | 
 | 9530 | #endif | 
 | 9531 |             first = NULL; | 
 | 9532 |             next = xmlXPathNextParent; | 
 | 9533 |             break; | 
 | 9534 |         case AXIS_PRECEDING: | 
 | 9535 | #ifdef DEBUG_STEP_NTH | 
 | 9536 |             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); | 
 | 9537 | #endif | 
 | 9538 |             first = NULL; | 
 | 9539 |             next = xmlXPathNextPrecedingInternal; | 
 | 9540 |             break; | 
 | 9541 |         case AXIS_PRECEDING_SIBLING: | 
 | 9542 | #ifdef DEBUG_STEP_NTH | 
 | 9543 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9544 |                             "axis 'preceding-sibling' "); | 
 | 9545 | #endif | 
 | 9546 |             first = NULL; | 
 | 9547 |             next = xmlXPathNextPrecedingSibling; | 
 | 9548 |             break; | 
 | 9549 |         case AXIS_SELF: | 
 | 9550 | #ifdef DEBUG_STEP_NTH | 
 | 9551 |             xmlGenericError(xmlGenericErrorContext, "axis 'self' "); | 
 | 9552 | #endif | 
 | 9553 |             first = NULL; | 
 | 9554 | 	    last = NULL; | 
 | 9555 |             next = xmlXPathNextSelf; | 
 | 9556 |             break; | 
 | 9557 |     } | 
 | 9558 |     if (next == NULL) | 
 | 9559 |         return(0); | 
 | 9560 |  | 
 | 9561 |     nodelist = obj->nodesetval; | 
 | 9562 |     if (nodelist == NULL) { | 
 | 9563 |         xmlXPathFreeObject(obj); | 
 | 9564 |         valuePush(ctxt, xmlXPathWrapNodeSet(NULL)); | 
 | 9565 |         return(0); | 
 | 9566 |     } | 
 | 9567 |     addNode = xmlXPathNodeSetAddUnique; | 
 | 9568 | #ifdef DEBUG_STEP_NTH | 
 | 9569 |     xmlGenericError(xmlGenericErrorContext, | 
 | 9570 |                     " context contains %d nodes\n", nodelist->nodeNr); | 
 | 9571 |     switch (test) { | 
 | 9572 |         case NODE_TEST_NONE: | 
 | 9573 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9574 |                             "           searching for none !!!\n"); | 
 | 9575 |             break; | 
 | 9576 |         case NODE_TEST_TYPE: | 
 | 9577 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9578 |                             "           searching for type %d\n", type); | 
 | 9579 |             break; | 
 | 9580 |         case NODE_TEST_PI: | 
 | 9581 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9582 |                             "           searching for PI !!!\n"); | 
 | 9583 |             break; | 
 | 9584 |         case NODE_TEST_ALL: | 
 | 9585 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9586 |                             "           searching for *\n"); | 
 | 9587 |             break; | 
 | 9588 |         case NODE_TEST_NS: | 
 | 9589 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9590 |                             "           searching for namespace %s\n", | 
 | 9591 |                             prefix); | 
 | 9592 |             break; | 
 | 9593 |         case NODE_TEST_NAME: | 
 | 9594 |             xmlGenericError(xmlGenericErrorContext, | 
 | 9595 |                             "           searching for name %s\n", name); | 
 | 9596 |             if (prefix != NULL) | 
 | 9597 |                 xmlGenericError(xmlGenericErrorContext, | 
 | 9598 |                                 "           with namespace %s\n", prefix); | 
 | 9599 |             break; | 
 | 9600 |     } | 
 | 9601 |     xmlGenericError(xmlGenericErrorContext, "Testing : "); | 
 | 9602 | #endif | 
 | 9603 |     /* | 
 | 9604 |      * 2.3 Node Tests | 
 | 9605 |      *  - For the attribute axis, the principal node type is attribute.  | 
 | 9606 |      *  - For the namespace axis, the principal node type is namespace.  | 
 | 9607 |      *  - For other axes, the principal node type is element.  | 
 | 9608 |      * | 
 | 9609 |      * A node test * is true for any node of the | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 9610 |      * principal node type. For example, child::* will | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9611 |      * select all element children of the context node | 
 | 9612 |      */ | 
 | 9613 |     tmp = ctxt->context->node; | 
 | 9614 |     list = xmlXPathNodeSetCreate(NULL); | 
 | 9615 |     for (i = 0; i < nodelist->nodeNr; i++) { | 
 | 9616 |         ctxt->context->node = nodelist->nodeTab[i]; | 
 | 9617 |  | 
 | 9618 |         cur = NULL; | 
 | 9619 |         n = 0; | 
 | 9620 |         do { | 
 | 9621 |             cur = next(ctxt, cur); | 
 | 9622 |             if (cur == NULL) | 
 | 9623 |                 break; | 
 | 9624 | 	    if ((first != NULL) && (*first == cur)) | 
 | 9625 | 		break; | 
 | 9626 | 	    if (((t % 256) == 0) && | 
 | 9627 | 	        (first != NULL) && (*first != NULL) && | 
 | 9628 | 		(xmlXPathCmpNodes(*first, cur) >= 0)) | 
 | 9629 | 		break; | 
 | 9630 | 	    if ((last != NULL) && (*last == cur)) | 
 | 9631 | 		break; | 
 | 9632 | 	    if (((t % 256) == 0) && | 
 | 9633 | 	        (last != NULL) && (*last != NULL) && | 
 | 9634 | 		(xmlXPathCmpNodes(cur, *last) >= 0)) | 
 | 9635 | 		break; | 
 | 9636 |             t++; | 
 | 9637 |             switch (test) { | 
 | 9638 |                 case NODE_TEST_NONE: | 
 | 9639 |                     ctxt->context->node = tmp; | 
 | 9640 |                     STRANGE return(0); | 
 | 9641 |                 case NODE_TEST_TYPE: | 
 | 9642 |                     if ((cur->type == type) || | 
 | 9643 |                         ((type == NODE_TYPE_NODE) && | 
 | 9644 |                          ((cur->type == XML_DOCUMENT_NODE) || | 
 | 9645 |                           (cur->type == XML_HTML_DOCUMENT_NODE) || | 
 | 9646 |                           (cur->type == XML_ELEMENT_NODE) || | 
 | 9647 |                           (cur->type == XML_PI_NODE) || | 
 | 9648 |                           (cur->type == XML_COMMENT_NODE) || | 
 | 9649 |                           (cur->type == XML_CDATA_SECTION_NODE) || | 
| Daniel Veillard | 8606bbb | 2002-11-12 12:36:52 +0000 | [diff] [blame] | 9650 |                           (cur->type == XML_TEXT_NODE))) || | 
 | 9651 | 			((type == NODE_TYPE_TEXT) && | 
 | 9652 | 			 (cur->type == XML_CDATA_SECTION_NODE))) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9653 |                         n++; | 
 | 9654 |                         if (n == indx) | 
 | 9655 |                             addNode(list, cur); | 
 | 9656 |                     } | 
 | 9657 |                     break; | 
 | 9658 |                 case NODE_TEST_PI: | 
 | 9659 |                     if (cur->type == XML_PI_NODE) { | 
 | 9660 |                         if ((name != NULL) && | 
 | 9661 |                             (!xmlStrEqual(name, cur->name))) | 
 | 9662 |                             break; | 
 | 9663 |                         n++; | 
 | 9664 |                         if (n == indx) | 
 | 9665 |                             addNode(list, cur); | 
 | 9666 |                     } | 
 | 9667 |                     break; | 
 | 9668 |                 case NODE_TEST_ALL: | 
 | 9669 |                     if (axis == AXIS_ATTRIBUTE) { | 
 | 9670 |                         if (cur->type == XML_ATTRIBUTE_NODE) { | 
 | 9671 |                             n++; | 
 | 9672 |                             if (n == indx) | 
 | 9673 |                                 addNode(list, cur); | 
 | 9674 |                         } | 
 | 9675 |                     } else if (axis == AXIS_NAMESPACE) { | 
 | 9676 |                         if (cur->type == XML_NAMESPACE_DECL) { | 
 | 9677 |                             n++; | 
 | 9678 |                             if (n == indx) | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 9679 | 				xmlXPathNodeSetAddNs(list, ctxt->context->node,  | 
 | 9680 | 						     (xmlNsPtr) cur); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9681 |                         } | 
 | 9682 |                     } else { | 
 | 9683 |                         if (cur->type == XML_ELEMENT_NODE) { | 
 | 9684 |                             if (prefix == NULL) { | 
 | 9685 |                                 n++; | 
 | 9686 |                                 if (n == indx) | 
 | 9687 |                                     addNode(list, cur); | 
 | 9688 |                             } else if ((cur->ns != NULL) && | 
 | 9689 |                                        (xmlStrEqual(URI, cur->ns->href))) { | 
 | 9690 |                                 n++; | 
 | 9691 |                                 if (n == indx) | 
 | 9692 |                                     addNode(list, cur); | 
 | 9693 |                             } | 
 | 9694 |                         } | 
 | 9695 |                     } | 
 | 9696 |                     break; | 
 | 9697 |                 case NODE_TEST_NS:{ | 
 | 9698 |                         TODO; | 
 | 9699 |                         break; | 
 | 9700 |                     } | 
 | 9701 |                 case NODE_TEST_NAME: | 
 | 9702 |                     switch (cur->type) { | 
 | 9703 |                         case XML_ELEMENT_NODE: | 
 | 9704 |                             if (xmlStrEqual(name, cur->name)) { | 
 | 9705 |                                 if (prefix == NULL) { | 
 | 9706 |                                     if (cur->ns == NULL) { | 
 | 9707 |                                         n++; | 
 | 9708 |                                         if (n == indx) | 
 | 9709 |                                             addNode(list, cur); | 
 | 9710 |                                     } | 
 | 9711 |                                 } else { | 
 | 9712 |                                     if ((cur->ns != NULL) && | 
 | 9713 |                                         (xmlStrEqual(URI, | 
 | 9714 |                                                      cur->ns->href))) { | 
 | 9715 |                                         n++; | 
 | 9716 |                                         if (n == indx) | 
 | 9717 |                                             addNode(list, cur); | 
 | 9718 |                                     } | 
 | 9719 |                                 } | 
 | 9720 |                             } | 
 | 9721 |                             break; | 
 | 9722 |                         case XML_ATTRIBUTE_NODE:{ | 
 | 9723 |                                 xmlAttrPtr attr = (xmlAttrPtr) cur; | 
 | 9724 |  | 
 | 9725 |                                 if (xmlStrEqual(name, attr->name)) { | 
 | 9726 |                                     if (prefix == NULL) { | 
 | 9727 |                                         if ((attr->ns == NULL) || | 
 | 9728 |                                             (attr->ns->prefix == NULL)) { | 
 | 9729 |                                             n++; | 
 | 9730 |                                             if (n == indx) | 
 | 9731 |                                                 addNode(list, cur); | 
 | 9732 |                                         } | 
 | 9733 |                                     } else { | 
 | 9734 |                                         if ((attr->ns != NULL) && | 
 | 9735 |                                             (xmlStrEqual(URI, | 
 | 9736 |                                                          attr->ns-> | 
 | 9737 |                                                          href))) { | 
 | 9738 |                                             n++; | 
 | 9739 |                                             if (n == indx) | 
 | 9740 |                                                 addNode(list, cur); | 
 | 9741 |                                         } | 
 | 9742 |                                     } | 
 | 9743 |                                 } | 
 | 9744 |                                 break; | 
 | 9745 |                             } | 
 | 9746 |                         case XML_NAMESPACE_DECL: | 
 | 9747 |                             if (cur->type == XML_NAMESPACE_DECL) { | 
 | 9748 |                                 xmlNsPtr ns = (xmlNsPtr) cur; | 
 | 9749 |  | 
 | 9750 |                                 if ((ns->prefix != NULL) && (name != NULL) | 
 | 9751 |                                     && (xmlStrEqual(ns->prefix, name))) { | 
 | 9752 |                                     n++; | 
 | 9753 |                                     if (n == indx) | 
| Daniel Veillard | 044fc6b | 2002-03-04 17:09:44 +0000 | [diff] [blame] | 9754 | 					xmlXPathNodeSetAddNs(list, | 
 | 9755 | 					   ctxt->context->node, (xmlNsPtr) cur); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9756 |                                 } | 
 | 9757 |                             } | 
 | 9758 |                             break; | 
 | 9759 |                         default: | 
 | 9760 |                             break; | 
 | 9761 |                     } | 
 | 9762 |                     break; | 
 | 9763 |                     break; | 
 | 9764 |             } | 
 | 9765 |         } while (n < indx); | 
 | 9766 |     } | 
 | 9767 |     ctxt->context->node = tmp; | 
 | 9768 | #ifdef DEBUG_STEP_NTH | 
 | 9769 |     xmlGenericError(xmlGenericErrorContext, | 
 | 9770 |                     "\nExamined %d nodes, found %d nodes at that step\n", | 
 | 9771 |                     t, list->nodeNr); | 
 | 9772 | #endif | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9773 |     valuePush(ctxt, xmlXPathWrapNodeSet(list)); | 
| Daniel Veillard | 0ab5cab | 2001-08-14 16:43:10 +0000 | [diff] [blame] | 9774 |     if ((obj->boolval) && (obj->user != NULL)) { | 
 | 9775 | 	ctxt->value->boolval = 1; | 
 | 9776 | 	ctxt->value->user = obj->user; | 
 | 9777 | 	obj->user = NULL; | 
 | 9778 | 	obj->boolval = 0; | 
 | 9779 |     } | 
 | 9780 |     xmlXPathFreeObject(obj); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9781 |     return(t); | 
 | 9782 | } | 
 | 9783 |  | 
 | 9784 | /** | 
 | 9785 |  * xmlXPathCompOpEvalFirst: | 
 | 9786 |  * @ctxt:  the XPath parser context with the compiled expression | 
 | 9787 |  * @op:  an XPath compiled operation | 
 | 9788 |  * @first:  the first elem found so far | 
 | 9789 |  * | 
 | 9790 |  * Evaluate the Precompiled XPath operation searching only the first | 
 | 9791 |  * element in document order | 
 | 9792 |  * | 
 | 9793 |  * Returns the number of examined objects. | 
 | 9794 |  */ | 
 | 9795 | static int | 
 | 9796 | xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, | 
 | 9797 |                         xmlXPathStepOpPtr op, xmlNodePtr * first) | 
 | 9798 | { | 
 | 9799 |     int total = 0, cur; | 
 | 9800 |     xmlXPathCompExprPtr comp; | 
 | 9801 |     xmlXPathObjectPtr arg1, arg2; | 
 | 9802 |  | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9803 |     CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9804 |     comp = ctxt->comp; | 
 | 9805 |     switch (op->op) { | 
 | 9806 |         case XPATH_OP_END: | 
 | 9807 |             return (0); | 
 | 9808 |         case XPATH_OP_UNION: | 
 | 9809 |             total = | 
 | 9810 |                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], | 
 | 9811 |                                         first); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9812 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9813 |             if ((ctxt->value != NULL) | 
 | 9814 |                 && (ctxt->value->type == XPATH_NODESET) | 
 | 9815 |                 && (ctxt->value->nodesetval != NULL) | 
 | 9816 |                 && (ctxt->value->nodesetval->nodeNr >= 1)) { | 
 | 9817 |                 /* | 
 | 9818 |                  * limit tree traversing to first node in the result | 
 | 9819 |                  */ | 
 | 9820 |                 xmlXPathNodeSetSort(ctxt->value->nodesetval); | 
 | 9821 |                 *first = ctxt->value->nodesetval->nodeTab[0]; | 
 | 9822 |             } | 
 | 9823 |             cur = | 
 | 9824 |                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], | 
 | 9825 |                                         first); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9826 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9827 |             CHECK_TYPE0(XPATH_NODESET); | 
 | 9828 |             arg2 = valuePop(ctxt); | 
 | 9829 |  | 
 | 9830 |             CHECK_TYPE0(XPATH_NODESET); | 
 | 9831 |             arg1 = valuePop(ctxt); | 
 | 9832 |  | 
 | 9833 |             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, | 
 | 9834 |                                                     arg2->nodesetval); | 
 | 9835 |             valuePush(ctxt, arg1); | 
 | 9836 |             xmlXPathFreeObject(arg2); | 
 | 9837 |             /* optimizer */ | 
 | 9838 | 	    if (total > cur) | 
 | 9839 | 		xmlXPathCompSwap(op); | 
 | 9840 |             return (total + cur); | 
 | 9841 |         case XPATH_OP_ROOT: | 
 | 9842 |             xmlXPathRoot(ctxt); | 
 | 9843 |             return (0); | 
 | 9844 |         case XPATH_OP_NODE: | 
 | 9845 |             if (op->ch1 != -1) | 
 | 9846 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9847 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9848 |             if (op->ch2 != -1) | 
 | 9849 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9850 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9851 |             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); | 
 | 9852 |             return (total); | 
 | 9853 |         case XPATH_OP_RESET: | 
 | 9854 |             if (op->ch1 != -1) | 
 | 9855 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9856 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9857 |             if (op->ch2 != -1) | 
 | 9858 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9859 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9860 |             ctxt->context->node = NULL; | 
 | 9861 |             return (total); | 
 | 9862 |         case XPATH_OP_COLLECT:{ | 
 | 9863 |                 if (op->ch1 == -1) | 
 | 9864 |                     return (total); | 
 | 9865 |  | 
 | 9866 |                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9867 | 		CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9868 |  | 
 | 9869 |                 /* | 
 | 9870 |                  * Optimization for [n] selection where n is a number | 
 | 9871 |                  */ | 
 | 9872 |                 if ((op->ch2 != -1) && | 
 | 9873 |                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && | 
 | 9874 |                     (comp->steps[op->ch2].ch1 == -1) && | 
 | 9875 |                     (comp->steps[op->ch2].ch2 != -1) && | 
 | 9876 |                     (comp->steps[comp->steps[op->ch2].ch2].op == | 
 | 9877 |                      XPATH_OP_VALUE)) { | 
 | 9878 |                     xmlXPathObjectPtr val; | 
 | 9879 |  | 
 | 9880 |                     val = comp->steps[comp->steps[op->ch2].ch2].value4; | 
 | 9881 |                     if ((val != NULL) && (val->type == XPATH_NUMBER)) { | 
 | 9882 |                         int indx = (int) val->floatval; | 
 | 9883 |  | 
 | 9884 |                         if (val->floatval == (float) indx) { | 
 | 9885 |                             xmlXPathNodeCollectAndTestNth(ctxt, op, indx, | 
 | 9886 |                                                           first, NULL); | 
 | 9887 |                             return (total); | 
 | 9888 |                         } | 
 | 9889 |                     } | 
 | 9890 |                 } | 
 | 9891 |                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL); | 
 | 9892 |                 return (total); | 
 | 9893 |             } | 
 | 9894 |         case XPATH_OP_VALUE: | 
 | 9895 |             valuePush(ctxt, | 
 | 9896 |                       xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); | 
 | 9897 |             return (0); | 
 | 9898 |         case XPATH_OP_SORT: | 
 | 9899 |             if (op->ch1 != -1) | 
 | 9900 |                 total += | 
 | 9901 |                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], | 
 | 9902 |                                             first); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9903 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9904 |             if ((ctxt->value != NULL) | 
 | 9905 |                 && (ctxt->value->type == XPATH_NODESET) | 
 | 9906 |                 && (ctxt->value->nodesetval != NULL)) | 
 | 9907 |                 xmlXPathNodeSetSort(ctxt->value->nodesetval); | 
 | 9908 |             return (total); | 
 | 9909 |         default: | 
 | 9910 |             return (xmlXPathCompOpEval(ctxt, op)); | 
 | 9911 |     } | 
 | 9912 | } | 
 | 9913 |  | 
 | 9914 | /** | 
 | 9915 |  * xmlXPathCompOpEvalLast: | 
 | 9916 |  * @ctxt:  the XPath parser context with the compiled expression | 
 | 9917 |  * @op:  an XPath compiled operation | 
 | 9918 |  * @last:  the last elem found so far | 
 | 9919 |  * | 
 | 9920 |  * Evaluate the Precompiled XPath operation searching only the last | 
 | 9921 |  * element in document order | 
 | 9922 |  * | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 9923 |  * Returns the number of nodes traversed | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9924 |  */ | 
 | 9925 | static int | 
 | 9926 | xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, | 
 | 9927 |                        xmlNodePtr * last) | 
 | 9928 | { | 
 | 9929 |     int total = 0, cur; | 
 | 9930 |     xmlXPathCompExprPtr comp; | 
 | 9931 |     xmlXPathObjectPtr arg1, arg2; | 
| William M. Brack | ce4fc56 | 2004-01-22 02:47:18 +0000 | [diff] [blame] | 9932 |     xmlNodePtr bak; | 
 | 9933 |     xmlDocPtr bakd; | 
 | 9934 |     int pp; | 
 | 9935 |     int cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9936 |  | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9937 |     CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9938 |     comp = ctxt->comp; | 
 | 9939 |     switch (op->op) { | 
 | 9940 |         case XPATH_OP_END: | 
 | 9941 |             return (0); | 
 | 9942 |         case XPATH_OP_UNION: | 
| William M. Brack | ce4fc56 | 2004-01-22 02:47:18 +0000 | [diff] [blame] | 9943 | 	    bakd = ctxt->context->doc; | 
 | 9944 | 	    bak = ctxt->context->node; | 
 | 9945 | 	    pp = ctxt->context->proximityPosition; | 
 | 9946 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9947 |             total = | 
 | 9948 |                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9949 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9950 |             if ((ctxt->value != NULL) | 
 | 9951 |                 && (ctxt->value->type == XPATH_NODESET) | 
 | 9952 |                 && (ctxt->value->nodesetval != NULL) | 
 | 9953 |                 && (ctxt->value->nodesetval->nodeNr >= 1)) { | 
 | 9954 |                 /* | 
 | 9955 |                  * limit tree traversing to first node in the result | 
 | 9956 |                  */ | 
 | 9957 |                 xmlXPathNodeSetSort(ctxt->value->nodesetval); | 
 | 9958 |                 *last = | 
 | 9959 |                     ctxt->value->nodesetval->nodeTab[ctxt->value-> | 
 | 9960 |                                                      nodesetval->nodeNr - | 
 | 9961 |                                                      1]; | 
 | 9962 |             } | 
| William M. Brack | ce4fc56 | 2004-01-22 02:47:18 +0000 | [diff] [blame] | 9963 | 	    ctxt->context->doc = bakd; | 
 | 9964 | 	    ctxt->context->node = bak; | 
 | 9965 | 	    ctxt->context->proximityPosition = pp; | 
 | 9966 | 	    ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9967 |             cur = | 
 | 9968 |                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9969 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9970 |             if ((ctxt->value != NULL) | 
 | 9971 |                 && (ctxt->value->type == XPATH_NODESET) | 
 | 9972 |                 && (ctxt->value->nodesetval != NULL) | 
 | 9973 |                 && (ctxt->value->nodesetval->nodeNr >= 1)) { | 
 | 9974 |             } | 
 | 9975 |             CHECK_TYPE0(XPATH_NODESET); | 
 | 9976 |             arg2 = valuePop(ctxt); | 
 | 9977 |  | 
 | 9978 |             CHECK_TYPE0(XPATH_NODESET); | 
 | 9979 |             arg1 = valuePop(ctxt); | 
 | 9980 |  | 
 | 9981 |             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, | 
 | 9982 |                                                     arg2->nodesetval); | 
 | 9983 |             valuePush(ctxt, arg1); | 
 | 9984 |             xmlXPathFreeObject(arg2); | 
 | 9985 |             /* optimizer */ | 
 | 9986 | 	    if (total > cur) | 
 | 9987 | 		xmlXPathCompSwap(op); | 
 | 9988 |             return (total + cur); | 
 | 9989 |         case XPATH_OP_ROOT: | 
 | 9990 |             xmlXPathRoot(ctxt); | 
 | 9991 |             return (0); | 
 | 9992 |         case XPATH_OP_NODE: | 
 | 9993 |             if (op->ch1 != -1) | 
 | 9994 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9995 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9996 |             if (op->ch2 != -1) | 
 | 9997 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 9998 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 9999 |             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); | 
 | 10000 |             return (total); | 
 | 10001 |         case XPATH_OP_RESET: | 
 | 10002 |             if (op->ch1 != -1) | 
 | 10003 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10004 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10005 |             if (op->ch2 != -1) | 
 | 10006 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10007 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10008 |             ctxt->context->node = NULL; | 
 | 10009 |             return (total); | 
 | 10010 |         case XPATH_OP_COLLECT:{ | 
 | 10011 |                 if (op->ch1 == -1) | 
 | 10012 |                     return (0); | 
 | 10013 |  | 
 | 10014 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10015 | 		CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10016 |  | 
 | 10017 |                 /* | 
 | 10018 |                  * Optimization for [n] selection where n is a number | 
 | 10019 |                  */ | 
 | 10020 |                 if ((op->ch2 != -1) && | 
 | 10021 |                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && | 
 | 10022 |                     (comp->steps[op->ch2].ch1 == -1) && | 
 | 10023 |                     (comp->steps[op->ch2].ch2 != -1) && | 
 | 10024 |                     (comp->steps[comp->steps[op->ch2].ch2].op == | 
 | 10025 |                      XPATH_OP_VALUE)) { | 
 | 10026 |                     xmlXPathObjectPtr val; | 
 | 10027 |  | 
 | 10028 |                     val = comp->steps[comp->steps[op->ch2].ch2].value4; | 
 | 10029 |                     if ((val != NULL) && (val->type == XPATH_NUMBER)) { | 
 | 10030 |                         int indx = (int) val->floatval; | 
 | 10031 |  | 
 | 10032 |                         if (val->floatval == (float) indx) { | 
 | 10033 |                             total += | 
 | 10034 |                                 xmlXPathNodeCollectAndTestNth(ctxt, op, | 
 | 10035 |                                                               indx, NULL, | 
 | 10036 |                                                               last); | 
 | 10037 |                             return (total); | 
 | 10038 |                         } | 
 | 10039 |                     } | 
 | 10040 |                 } | 
 | 10041 |                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last); | 
 | 10042 |                 return (total); | 
 | 10043 |             } | 
 | 10044 |         case XPATH_OP_VALUE: | 
 | 10045 |             valuePush(ctxt, | 
 | 10046 |                       xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); | 
 | 10047 |             return (0); | 
 | 10048 |         case XPATH_OP_SORT: | 
 | 10049 |             if (op->ch1 != -1) | 
 | 10050 |                 total += | 
 | 10051 |                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], | 
 | 10052 |                                            last); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10053 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10054 |             if ((ctxt->value != NULL) | 
 | 10055 |                 && (ctxt->value->type == XPATH_NODESET) | 
 | 10056 |                 && (ctxt->value->nodesetval != NULL)) | 
 | 10057 |                 xmlXPathNodeSetSort(ctxt->value->nodesetval); | 
 | 10058 |             return (total); | 
 | 10059 |         default: | 
 | 10060 |             return (xmlXPathCompOpEval(ctxt, op)); | 
 | 10061 |     } | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 10062 | } | 
 | 10063 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 10064 | /** | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10065 |  * xmlXPathCompOpEval: | 
 | 10066 |  * @ctxt:  the XPath parser context with the compiled expression | 
 | 10067 |  * @op:  an XPath compiled operation | 
 | 10068 |  * | 
 | 10069 |  * Evaluate the Precompiled XPath operation | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10070 |  * Returns the number of nodes traversed | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10071 |  */ | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10072 | static int | 
 | 10073 | xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) | 
 | 10074 | { | 
 | 10075 |     int total = 0; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10076 |     int equal, ret; | 
 | 10077 |     xmlXPathCompExprPtr comp; | 
 | 10078 |     xmlXPathObjectPtr arg1, arg2; | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10079 |     xmlNodePtr bak; | 
 | 10080 |     xmlDocPtr bakd; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10081 |     int pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10082 |     int cs; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10083 |  | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10084 |     CHECK_ERROR0; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10085 |     comp = ctxt->comp; | 
 | 10086 |     switch (op->op) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10087 |         case XPATH_OP_END: | 
 | 10088 |             return (0); | 
 | 10089 |         case XPATH_OP_AND: | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10090 | 	    bakd = ctxt->context->doc; | 
 | 10091 | 	    bak = ctxt->context->node; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10092 | 	    pp = ctxt->context->proximityPosition; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10093 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10094 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10095 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10096 |             xmlXPathBooleanFunction(ctxt, 1); | 
 | 10097 |             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) | 
 | 10098 |                 return (total); | 
 | 10099 |             arg2 = valuePop(ctxt); | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10100 | 	    ctxt->context->doc = bakd; | 
 | 10101 | 	    ctxt->context->node = bak; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10102 | 	    ctxt->context->proximityPosition = pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10103 | 	    ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10104 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10105 | 	    if (ctxt->error) { | 
 | 10106 | 		xmlXPathFreeObject(arg2); | 
 | 10107 | 		return(0); | 
 | 10108 | 	    } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10109 |             xmlXPathBooleanFunction(ctxt, 1); | 
 | 10110 |             arg1 = valuePop(ctxt); | 
 | 10111 |             arg1->boolval &= arg2->boolval; | 
 | 10112 |             valuePush(ctxt, arg1); | 
 | 10113 |             xmlXPathFreeObject(arg2); | 
 | 10114 |             return (total); | 
 | 10115 |         case XPATH_OP_OR: | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10116 | 	    bakd = ctxt->context->doc; | 
 | 10117 | 	    bak = ctxt->context->node; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10118 | 	    pp = ctxt->context->proximityPosition; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10119 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10120 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10121 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10122 |             xmlXPathBooleanFunction(ctxt, 1); | 
 | 10123 |             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) | 
 | 10124 |                 return (total); | 
 | 10125 |             arg2 = valuePop(ctxt); | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10126 | 	    ctxt->context->doc = bakd; | 
 | 10127 | 	    ctxt->context->node = bak; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10128 | 	    ctxt->context->proximityPosition = pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10129 | 	    ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10130 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10131 | 	    if (ctxt->error) { | 
 | 10132 | 		xmlXPathFreeObject(arg2); | 
 | 10133 | 		return(0); | 
 | 10134 | 	    } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10135 |             xmlXPathBooleanFunction(ctxt, 1); | 
 | 10136 |             arg1 = valuePop(ctxt); | 
 | 10137 |             arg1->boolval |= arg2->boolval; | 
 | 10138 |             valuePush(ctxt, arg1); | 
 | 10139 |             xmlXPathFreeObject(arg2); | 
 | 10140 |             return (total); | 
 | 10141 |         case XPATH_OP_EQUAL: | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10142 | 	    bakd = ctxt->context->doc; | 
 | 10143 | 	    bak = ctxt->context->node; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10144 | 	    pp = ctxt->context->proximityPosition; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10145 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10146 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10147 | 	    CHECK_ERROR0; | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10148 | 	    ctxt->context->doc = bakd; | 
 | 10149 | 	    ctxt->context->node = bak; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10150 | 	    ctxt->context->proximityPosition = pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10151 | 	    ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10152 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10153 | 	    CHECK_ERROR0; | 
| William M. Brack | 0c022ad | 2002-07-12 00:56:01 +0000 | [diff] [blame] | 10154 | 	    if (op->value) | 
 | 10155 |         	equal = xmlXPathEqualValues(ctxt); | 
 | 10156 | 	    else | 
 | 10157 | 		equal = xmlXPathNotEqualValues(ctxt); | 
 | 10158 | 	    valuePush(ctxt, xmlXPathNewBoolean(equal)); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10159 |             return (total); | 
 | 10160 |         case XPATH_OP_CMP: | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10161 | 	    bakd = ctxt->context->doc; | 
 | 10162 | 	    bak = ctxt->context->node; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10163 | 	    pp = ctxt->context->proximityPosition; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10164 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10165 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10166 | 	    CHECK_ERROR0; | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10167 | 	    ctxt->context->doc = bakd; | 
 | 10168 | 	    ctxt->context->node = bak; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10169 | 	    ctxt->context->proximityPosition = pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10170 | 	    ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10171 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10172 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10173 |             ret = xmlXPathCompareValues(ctxt, op->value, op->value2); | 
 | 10174 |             valuePush(ctxt, xmlXPathNewBoolean(ret)); | 
 | 10175 |             return (total); | 
 | 10176 |         case XPATH_OP_PLUS: | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10177 | 	    bakd = ctxt->context->doc; | 
 | 10178 | 	    bak = ctxt->context->node; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10179 | 	    pp = ctxt->context->proximityPosition; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10180 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10181 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10182 | 	    CHECK_ERROR0; | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10183 |             if (op->ch2 != -1) { | 
 | 10184 | 		ctxt->context->doc = bakd; | 
 | 10185 | 		ctxt->context->node = bak; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10186 | 		ctxt->context->proximityPosition = pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10187 | 		ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10188 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10189 | 	    } | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10190 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10191 |             if (op->value == 0) | 
 | 10192 |                 xmlXPathSubValues(ctxt); | 
 | 10193 |             else if (op->value == 1) | 
 | 10194 |                 xmlXPathAddValues(ctxt); | 
 | 10195 |             else if (op->value == 2) | 
 | 10196 |                 xmlXPathValueFlipSign(ctxt); | 
 | 10197 |             else if (op->value == 3) { | 
 | 10198 |                 CAST_TO_NUMBER; | 
 | 10199 |                 CHECK_TYPE0(XPATH_NUMBER); | 
 | 10200 |             } | 
 | 10201 |             return (total); | 
 | 10202 |         case XPATH_OP_MULT: | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10203 | 	    bakd = ctxt->context->doc; | 
 | 10204 | 	    bak = ctxt->context->node; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10205 | 	    pp = ctxt->context->proximityPosition; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10206 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10207 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10208 | 	    CHECK_ERROR0; | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10209 | 	    ctxt->context->doc = bakd; | 
 | 10210 | 	    ctxt->context->node = bak; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10211 | 	    ctxt->context->proximityPosition = pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10212 | 	    ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10213 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10214 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10215 |             if (op->value == 0) | 
 | 10216 |                 xmlXPathMultValues(ctxt); | 
 | 10217 |             else if (op->value == 1) | 
 | 10218 |                 xmlXPathDivValues(ctxt); | 
 | 10219 |             else if (op->value == 2) | 
 | 10220 |                 xmlXPathModValues(ctxt); | 
 | 10221 |             return (total); | 
 | 10222 |         case XPATH_OP_UNION: | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10223 | 	    bakd = ctxt->context->doc; | 
 | 10224 | 	    bak = ctxt->context->node; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10225 | 	    pp = ctxt->context->proximityPosition; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10226 | 	    cs = ctxt->context->contextSize; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10227 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10228 | 	    CHECK_ERROR0; | 
| Daniel Veillard | 7089d6b | 2002-03-29 17:28:10 +0000 | [diff] [blame] | 10229 | 	    ctxt->context->doc = bakd; | 
 | 10230 | 	    ctxt->context->node = bak; | 
| William M. Brack | 6000af5 | 2002-06-28 11:43:13 +0000 | [diff] [blame] | 10231 | 	    ctxt->context->proximityPosition = pp; | 
| William M. Brack | 692092b | 2002-06-28 15:01:24 +0000 | [diff] [blame] | 10232 | 	    ctxt->context->contextSize = cs; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10233 |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10234 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10235 |             CHECK_TYPE0(XPATH_NODESET); | 
 | 10236 |             arg2 = valuePop(ctxt); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10237 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10238 |             CHECK_TYPE0(XPATH_NODESET); | 
 | 10239 |             arg1 = valuePop(ctxt); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10240 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10241 |             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, | 
 | 10242 |                                                     arg2->nodesetval); | 
 | 10243 |             valuePush(ctxt, arg1); | 
 | 10244 |             xmlXPathFreeObject(arg2); | 
 | 10245 |             return (total); | 
 | 10246 |         case XPATH_OP_ROOT: | 
 | 10247 |             xmlXPathRoot(ctxt); | 
 | 10248 |             return (total); | 
 | 10249 |         case XPATH_OP_NODE: | 
 | 10250 |             if (op->ch1 != -1) | 
 | 10251 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10252 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10253 |             if (op->ch2 != -1) | 
 | 10254 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10255 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10256 |             valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); | 
 | 10257 |             return (total); | 
 | 10258 |         case XPATH_OP_RESET: | 
 | 10259 |             if (op->ch1 != -1) | 
 | 10260 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10261 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10262 |             if (op->ch2 != -1) | 
 | 10263 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10264 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10265 |             ctxt->context->node = NULL; | 
 | 10266 |             return (total); | 
 | 10267 |         case XPATH_OP_COLLECT:{ | 
 | 10268 |                 if (op->ch1 == -1) | 
 | 10269 |                     return (total); | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 10270 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10271 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10272 | 		CHECK_ERROR0; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10273 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10274 |                 /* | 
 | 10275 |                  * Optimization for [n] selection where n is a number | 
 | 10276 |                  */ | 
 | 10277 |                 if ((op->ch2 != -1) && | 
 | 10278 |                     (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && | 
 | 10279 |                     (comp->steps[op->ch2].ch1 == -1) && | 
 | 10280 |                     (comp->steps[op->ch2].ch2 != -1) && | 
 | 10281 |                     (comp->steps[comp->steps[op->ch2].ch2].op == | 
 | 10282 |                      XPATH_OP_VALUE)) { | 
 | 10283 |                     xmlXPathObjectPtr val; | 
| Daniel Veillard | 42596ad | 2001-05-22 16:57:14 +0000 | [diff] [blame] | 10284 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10285 |                     val = comp->steps[comp->steps[op->ch2].ch2].value4; | 
 | 10286 |                     if ((val != NULL) && (val->type == XPATH_NUMBER)) { | 
 | 10287 |                         int indx = (int) val->floatval; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10288 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10289 |                         if (val->floatval == (float) indx) { | 
 | 10290 |                             total += | 
 | 10291 |                                 xmlXPathNodeCollectAndTestNth(ctxt, op, | 
 | 10292 |                                                               indx, NULL, | 
 | 10293 |                                                               NULL); | 
 | 10294 |                             return (total); | 
 | 10295 |                         } | 
 | 10296 |                     } | 
 | 10297 |                 } | 
 | 10298 |                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL); | 
 | 10299 |                 return (total); | 
 | 10300 |             } | 
 | 10301 |         case XPATH_OP_VALUE: | 
 | 10302 |             valuePush(ctxt, | 
 | 10303 |                       xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); | 
 | 10304 |             return (total); | 
 | 10305 |         case XPATH_OP_VARIABLE:{ | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10306 | 		xmlXPathObjectPtr val; | 
 | 10307 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10308 |                 if (op->ch1 != -1) | 
 | 10309 |                     total += | 
 | 10310 |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10311 |                 if (op->value5 == NULL) { | 
 | 10312 | 		    val = xmlXPathVariableLookup(ctxt->context, op->value4); | 
 | 10313 | 		    if (val == NULL) { | 
 | 10314 | 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; | 
 | 10315 | 			return(0); | 
 | 10316 | 		    } | 
 | 10317 |                     valuePush(ctxt, val); | 
 | 10318 | 		} else { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10319 |                     const xmlChar *URI; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10320 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10321 |                     URI = xmlXPathNsLookup(ctxt->context, op->value5); | 
 | 10322 |                     if (URI == NULL) { | 
 | 10323 |                         xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 10324 |                                         "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10325 |                                         op->value4, op->value5); | 
 | 10326 |                         return (total); | 
 | 10327 |                     } | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10328 | 		    val = xmlXPathVariableLookupNS(ctxt->context, | 
 | 10329 |                                                        op->value4, URI); | 
 | 10330 | 		    if (val == NULL) { | 
 | 10331 | 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; | 
 | 10332 | 			return(0); | 
 | 10333 | 		    } | 
 | 10334 |                     valuePush(ctxt, val); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10335 |                 } | 
 | 10336 |                 return (total); | 
 | 10337 |             } | 
 | 10338 |         case XPATH_OP_FUNCTION:{ | 
 | 10339 |                 xmlXPathFunction func; | 
 | 10340 |                 const xmlChar *oldFunc, *oldFuncURI; | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10341 | 		int i; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10342 |  | 
 | 10343 |                 if (op->ch1 != -1) | 
 | 10344 |                     total += | 
 | 10345 |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10346 | 		if (ctxt->valueNr < op->value) { | 
 | 10347 | 		    xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 10348 | 			    "xmlXPathCompOpEval: parameter error\n"); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10349 | 		    ctxt->error = XPATH_INVALID_OPERAND; | 
 | 10350 | 		    return (total); | 
 | 10351 | 		} | 
 | 10352 | 		for (i = 0; i < op->value; i++) | 
 | 10353 | 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { | 
 | 10354 | 			xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 10355 | 				"xmlXPathCompOpEval: parameter error\n"); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10356 | 			ctxt->error = XPATH_INVALID_OPERAND; | 
 | 10357 | 			return (total); | 
 | 10358 | 		    } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10359 |                 if (op->cache != NULL) | 
 | 10360 |                     func = (xmlXPathFunction) op->cache; | 
 | 10361 |                 else { | 
 | 10362 |                     const xmlChar *URI = NULL; | 
 | 10363 |  | 
 | 10364 |                     if (op->value5 == NULL) | 
 | 10365 |                         func = | 
 | 10366 |                             xmlXPathFunctionLookup(ctxt->context, | 
 | 10367 |                                                    op->value4); | 
 | 10368 |                     else { | 
 | 10369 |                         URI = xmlXPathNsLookup(ctxt->context, op->value5); | 
 | 10370 |                         if (URI == NULL) { | 
 | 10371 |                             xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 10372 |                                             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10373 |                                             op->value4, op->value5); | 
 | 10374 |                             return (total); | 
 | 10375 |                         } | 
 | 10376 |                         func = xmlXPathFunctionLookupNS(ctxt->context, | 
 | 10377 |                                                         op->value4, URI); | 
 | 10378 |                     } | 
 | 10379 |                     if (func == NULL) { | 
 | 10380 |                         xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 10381 |                                         "xmlXPathCompOpEval: function %s not found\n", | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10382 |                                         op->value4); | 
 | 10383 |                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10384 |                     } | 
 | 10385 |                     op->cache = (void *) func; | 
 | 10386 |                     op->cacheURI = (void *) URI; | 
 | 10387 |                 } | 
 | 10388 |                 oldFunc = ctxt->context->function; | 
 | 10389 |                 oldFuncURI = ctxt->context->functionURI; | 
 | 10390 |                 ctxt->context->function = op->value4; | 
 | 10391 |                 ctxt->context->functionURI = op->cacheURI; | 
 | 10392 |                 func(ctxt, op->value); | 
 | 10393 |                 ctxt->context->function = oldFunc; | 
 | 10394 |                 ctxt->context->functionURI = oldFuncURI; | 
 | 10395 |                 return (total); | 
 | 10396 |             } | 
 | 10397 |         case XPATH_OP_ARG: | 
| Daniel Veillard | 088bf11 | 2002-05-14 11:03:59 +0000 | [diff] [blame] | 10398 | 	    bakd = ctxt->context->doc; | 
 | 10399 | 	    bak = ctxt->context->node; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10400 |             if (op->ch1 != -1) | 
 | 10401 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 088bf11 | 2002-05-14 11:03:59 +0000 | [diff] [blame] | 10402 | 	    ctxt->context->doc = bakd; | 
 | 10403 | 	    ctxt->context->node = bak; | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10404 | 	    CHECK_ERROR0; | 
| William M. Brack | 72ee48d | 2003-12-30 08:30:19 +0000 | [diff] [blame] | 10405 |             if (op->ch2 != -1) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10406 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); | 
| William M. Brack | 72ee48d | 2003-12-30 08:30:19 +0000 | [diff] [blame] | 10407 | 	        ctxt->context->doc = bakd; | 
 | 10408 | 	        ctxt->context->node = bak; | 
 | 10409 | 	        CHECK_ERROR0; | 
 | 10410 | 	    } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10411 |             return (total); | 
 | 10412 |         case XPATH_OP_PREDICATE: | 
 | 10413 |         case XPATH_OP_FILTER:{ | 
 | 10414 |                 xmlXPathObjectPtr res; | 
 | 10415 |                 xmlXPathObjectPtr obj, tmp; | 
 | 10416 |                 xmlNodeSetPtr newset = NULL; | 
 | 10417 |                 xmlNodeSetPtr oldset; | 
 | 10418 |                 xmlNodePtr oldnode; | 
| William M. Brack | 3794b9e | 2004-07-13 15:06:20 +0000 | [diff] [blame] | 10419 | 		xmlDocPtr oldDoc; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10420 |                 int i; | 
 | 10421 |  | 
 | 10422 |                 /* | 
 | 10423 |                  * Optimization for ()[1] selection i.e. the first elem | 
 | 10424 |                  */ | 
 | 10425 |                 if ((op->ch1 != -1) && (op->ch2 != -1) && | 
 | 10426 |                     (comp->steps[op->ch1].op == XPATH_OP_SORT) && | 
 | 10427 |                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { | 
 | 10428 |                     xmlXPathObjectPtr val; | 
 | 10429 |  | 
 | 10430 |                     val = comp->steps[op->ch2].value4; | 
 | 10431 |                     if ((val != NULL) && (val->type == XPATH_NUMBER) && | 
 | 10432 |                         (val->floatval == 1.0)) { | 
 | 10433 |                         xmlNodePtr first = NULL; | 
 | 10434 |  | 
 | 10435 |                         total += | 
 | 10436 |                             xmlXPathCompOpEvalFirst(ctxt, | 
 | 10437 |                                                     &comp->steps[op->ch1], | 
 | 10438 |                                                     &first); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10439 | 			CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10440 |                         /* | 
 | 10441 |                          * The nodeset should be in document order, | 
 | 10442 |                          * Keep only the first value | 
 | 10443 |                          */ | 
 | 10444 |                         if ((ctxt->value != NULL) && | 
 | 10445 |                             (ctxt->value->type == XPATH_NODESET) && | 
 | 10446 |                             (ctxt->value->nodesetval != NULL) && | 
 | 10447 |                             (ctxt->value->nodesetval->nodeNr > 1)) | 
 | 10448 |                             ctxt->value->nodesetval->nodeNr = 1; | 
 | 10449 |                         return (total); | 
 | 10450 |                     } | 
 | 10451 |                 } | 
 | 10452 |                 /* | 
 | 10453 |                  * Optimization for ()[last()] selection i.e. the last elem | 
 | 10454 |                  */ | 
 | 10455 |                 if ((op->ch1 != -1) && (op->ch2 != -1) && | 
 | 10456 |                     (comp->steps[op->ch1].op == XPATH_OP_SORT) && | 
 | 10457 |                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) { | 
 | 10458 |                     int f = comp->steps[op->ch2].ch1; | 
 | 10459 |  | 
 | 10460 |                     if ((f != -1) && | 
 | 10461 |                         (comp->steps[f].op == XPATH_OP_FUNCTION) && | 
 | 10462 |                         (comp->steps[f].value5 == NULL) && | 
 | 10463 |                         (comp->steps[f].value == 0) && | 
 | 10464 |                         (comp->steps[f].value4 != NULL) && | 
 | 10465 |                         (xmlStrEqual | 
 | 10466 |                          (comp->steps[f].value4, BAD_CAST "last"))) { | 
 | 10467 |                         xmlNodePtr last = NULL; | 
 | 10468 |  | 
 | 10469 |                         total += | 
 | 10470 |                             xmlXPathCompOpEvalLast(ctxt, | 
 | 10471 |                                                    &comp->steps[op->ch1], | 
 | 10472 |                                                    &last); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10473 | 			CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10474 |                         /* | 
 | 10475 |                          * The nodeset should be in document order, | 
 | 10476 |                          * Keep only the last value | 
 | 10477 |                          */ | 
 | 10478 |                         if ((ctxt->value != NULL) && | 
 | 10479 |                             (ctxt->value->type == XPATH_NODESET) && | 
 | 10480 |                             (ctxt->value->nodesetval != NULL) && | 
 | 10481 |                             (ctxt->value->nodesetval->nodeTab != NULL) && | 
 | 10482 |                             (ctxt->value->nodesetval->nodeNr > 1)) { | 
 | 10483 |                             ctxt->value->nodesetval->nodeTab[0] = | 
 | 10484 |                                 ctxt->value->nodesetval->nodeTab[ctxt-> | 
 | 10485 |                                                                  value-> | 
 | 10486 |                                                                  nodesetval-> | 
 | 10487 |                                                                  nodeNr - | 
 | 10488 |                                                                  1]; | 
 | 10489 |                             ctxt->value->nodesetval->nodeNr = 1; | 
 | 10490 |                         } | 
 | 10491 |                         return (total); | 
 | 10492 |                     } | 
 | 10493 |                 } | 
 | 10494 |  | 
 | 10495 |                 if (op->ch1 != -1) | 
 | 10496 |                     total += | 
 | 10497 |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10498 | 		CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10499 |                 if (op->ch2 == -1) | 
 | 10500 |                     return (total); | 
 | 10501 |                 if (ctxt->value == NULL) | 
 | 10502 |                     return (total); | 
 | 10503 |  | 
 | 10504 |                 oldnode = ctxt->context->node; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10505 |  | 
 | 10506 | #ifdef LIBXML_XPTR_ENABLED | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10507 |                 /* | 
 | 10508 |                  * Hum are we filtering the result of an XPointer expression | 
 | 10509 |                  */ | 
 | 10510 |                 if (ctxt->value->type == XPATH_LOCATIONSET) { | 
 | 10511 |                     xmlLocationSetPtr newlocset = NULL; | 
 | 10512 |                     xmlLocationSetPtr oldlocset; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10513 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10514 |                     /* | 
 | 10515 |                      * Extract the old locset, and then evaluate the result of the | 
 | 10516 |                      * expression for all the element in the locset. use it to grow | 
 | 10517 |                      * up a new locset. | 
 | 10518 |                      */ | 
 | 10519 |                     CHECK_TYPE0(XPATH_LOCATIONSET); | 
 | 10520 |                     obj = valuePop(ctxt); | 
 | 10521 |                     oldlocset = obj->user; | 
 | 10522 |                     ctxt->context->node = NULL; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10523 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10524 |                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { | 
 | 10525 |                         ctxt->context->contextSize = 0; | 
 | 10526 |                         ctxt->context->proximityPosition = 0; | 
 | 10527 |                         if (op->ch2 != -1) | 
 | 10528 |                             total += | 
 | 10529 |                                 xmlXPathCompOpEval(ctxt, | 
 | 10530 |                                                    &comp->steps[op->ch2]); | 
 | 10531 |                         res = valuePop(ctxt); | 
 | 10532 |                         if (res != NULL) | 
 | 10533 |                             xmlXPathFreeObject(res); | 
 | 10534 |                         valuePush(ctxt, obj); | 
 | 10535 |                         CHECK_ERROR0; | 
 | 10536 |                         return (total); | 
 | 10537 |                     } | 
 | 10538 |                     newlocset = xmlXPtrLocationSetCreate(NULL); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10539 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10540 |                     for (i = 0; i < oldlocset->locNr; i++) { | 
 | 10541 |                         /* | 
 | 10542 |                          * Run the evaluation with a node list made of a | 
 | 10543 |                          * single item in the nodelocset. | 
 | 10544 |                          */ | 
 | 10545 |                         ctxt->context->node = oldlocset->locTab[i]->user; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10546 |                         ctxt->context->contextSize = oldlocset->locNr; | 
 | 10547 |                         ctxt->context->proximityPosition = i + 1; | 
| William M. Brack | f7eb794 | 2003-12-31 07:59:17 +0000 | [diff] [blame] | 10548 |                         tmp = xmlXPathNewNodeSet(ctxt->context->node); | 
 | 10549 |                         valuePush(ctxt, tmp); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10550 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10551 |                         if (op->ch2 != -1) | 
 | 10552 |                             total += | 
 | 10553 |                                 xmlXPathCompOpEval(ctxt, | 
 | 10554 |                                                    &comp->steps[op->ch2]); | 
 | 10555 |                         CHECK_ERROR0; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10556 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10557 |                         /* | 
 | 10558 |                          * The result of the evaluation need to be tested to | 
 | 10559 |                          * decided whether the filter succeeded or not | 
 | 10560 |                          */ | 
 | 10561 |                         res = valuePop(ctxt); | 
 | 10562 |                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) { | 
 | 10563 |                             xmlXPtrLocationSetAdd(newlocset, | 
 | 10564 |                                                   xmlXPathObjectCopy | 
 | 10565 |                                                   (oldlocset->locTab[i])); | 
 | 10566 |                         } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10567 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10568 |                         /* | 
 | 10569 |                          * Cleanup | 
 | 10570 |                          */ | 
 | 10571 |                         if (res != NULL) | 
 | 10572 |                             xmlXPathFreeObject(res); | 
 | 10573 |                         if (ctxt->value == tmp) { | 
 | 10574 |                             res = valuePop(ctxt); | 
 | 10575 |                             xmlXPathFreeObject(res); | 
 | 10576 |                         } | 
 | 10577 |  | 
 | 10578 |                         ctxt->context->node = NULL; | 
 | 10579 |                     } | 
 | 10580 |  | 
 | 10581 |                     /* | 
 | 10582 |                      * The result is used as the new evaluation locset. | 
 | 10583 |                      */ | 
 | 10584 |                     xmlXPathFreeObject(obj); | 
 | 10585 |                     ctxt->context->node = NULL; | 
 | 10586 |                     ctxt->context->contextSize = -1; | 
 | 10587 |                     ctxt->context->proximityPosition = -1; | 
 | 10588 |                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); | 
 | 10589 |                     ctxt->context->node = oldnode; | 
 | 10590 |                     return (total); | 
 | 10591 |                 } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10592 | #endif /* LIBXML_XPTR_ENABLED */ | 
 | 10593 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10594 |                 /* | 
 | 10595 |                  * Extract the old set, and then evaluate the result of the | 
 | 10596 |                  * expression for all the element in the set. use it to grow | 
 | 10597 |                  * up a new set. | 
 | 10598 |                  */ | 
 | 10599 |                 CHECK_TYPE0(XPATH_NODESET); | 
 | 10600 |                 obj = valuePop(ctxt); | 
 | 10601 |                 oldset = obj->nodesetval; | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 10602 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10603 |                 oldnode = ctxt->context->node; | 
| William M. Brack | 3794b9e | 2004-07-13 15:06:20 +0000 | [diff] [blame] | 10604 | 		oldDoc = ctxt->context->doc; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10605 |                 ctxt->context->node = NULL; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10606 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10607 |                 if ((oldset == NULL) || (oldset->nodeNr == 0)) { | 
 | 10608 |                     ctxt->context->contextSize = 0; | 
 | 10609 |                     ctxt->context->proximityPosition = 0; | 
| William M. Brack | 8fad8bf | 2004-06-02 08:26:25 +0000 | [diff] [blame] | 10610 | /* | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10611 |                     if (op->ch2 != -1) | 
 | 10612 |                         total += | 
 | 10613 |                             xmlXPathCompOpEval(ctxt, | 
 | 10614 |                                                &comp->steps[op->ch2]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10615 | 		    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10616 |                     res = valuePop(ctxt); | 
 | 10617 |                     if (res != NULL) | 
 | 10618 |                         xmlXPathFreeObject(res); | 
| William M. Brack | 8fad8bf | 2004-06-02 08:26:25 +0000 | [diff] [blame] | 10619 | */ | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10620 |                     valuePush(ctxt, obj); | 
 | 10621 |                     ctxt->context->node = oldnode; | 
 | 10622 |                     CHECK_ERROR0; | 
 | 10623 |                 } else { | 
 | 10624 |                     /* | 
 | 10625 |                      * Initialize the new set. | 
| William M. Brack | 3794b9e | 2004-07-13 15:06:20 +0000 | [diff] [blame] | 10626 | 		     * Also set the xpath document in case things like | 
 | 10627 | 		     * key() evaluation are attempted on the predicate | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10628 |                      */ | 
 | 10629 |                     newset = xmlXPathNodeSetCreate(NULL); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10630 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10631 |                     for (i = 0; i < oldset->nodeNr; i++) { | 
 | 10632 |                         /* | 
 | 10633 |                          * Run the evaluation with a node list made of | 
 | 10634 |                          * a single item in the nodeset. | 
 | 10635 |                          */ | 
 | 10636 |                         ctxt->context->node = oldset->nodeTab[i]; | 
| William M. Brack | 3794b9e | 2004-07-13 15:06:20 +0000 | [diff] [blame] | 10637 | 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && | 
 | 10638 | 			    (oldset->nodeTab[i]->doc != NULL)) | 
 | 10639 | 		            ctxt->context->doc = oldset->nodeTab[i]->doc; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10640 |                         tmp = xmlXPathNewNodeSet(ctxt->context->node); | 
 | 10641 |                         valuePush(ctxt, tmp); | 
 | 10642 |                         ctxt->context->contextSize = oldset->nodeNr; | 
 | 10643 |                         ctxt->context->proximityPosition = i + 1; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10644 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10645 |                         if (op->ch2 != -1) | 
 | 10646 |                             total += | 
 | 10647 |                                 xmlXPathCompOpEval(ctxt, | 
 | 10648 |                                                    &comp->steps[op->ch2]); | 
 | 10649 |                         CHECK_ERROR0; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10650 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10651 |                         /* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10652 |                          * The result of the evaluation needs to be tested to | 
 | 10653 |                          * decide whether the filter succeeded or not | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10654 |                          */ | 
 | 10655 |                         res = valuePop(ctxt); | 
 | 10656 |                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) { | 
 | 10657 |                             xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); | 
 | 10658 |                         } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10659 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10660 |                         /* | 
 | 10661 |                          * Cleanup | 
 | 10662 |                          */ | 
 | 10663 |                         if (res != NULL) | 
 | 10664 |                             xmlXPathFreeObject(res); | 
 | 10665 |                         if (ctxt->value == tmp) { | 
 | 10666 |                             res = valuePop(ctxt); | 
 | 10667 |                             xmlXPathFreeObject(res); | 
 | 10668 |                         } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10669 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10670 |                         ctxt->context->node = NULL; | 
 | 10671 |                     } | 
 | 10672 |  | 
 | 10673 |                     /* | 
 | 10674 |                      * The result is used as the new evaluation set. | 
 | 10675 |                      */ | 
 | 10676 |                     xmlXPathFreeObject(obj); | 
 | 10677 |                     ctxt->context->node = NULL; | 
 | 10678 |                     ctxt->context->contextSize = -1; | 
 | 10679 |                     ctxt->context->proximityPosition = -1; | 
| William M. Brack | 3794b9e | 2004-07-13 15:06:20 +0000 | [diff] [blame] | 10680 | 		    /* may want to move this past the '}' later */ | 
 | 10681 | 		    ctxt->context->doc = oldDoc; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10682 |                     valuePush(ctxt, xmlXPathWrapNodeSet(newset)); | 
 | 10683 |                 } | 
 | 10684 |                 ctxt->context->node = oldnode; | 
 | 10685 |                 return (total); | 
 | 10686 |             } | 
 | 10687 |         case XPATH_OP_SORT: | 
 | 10688 |             if (op->ch1 != -1) | 
 | 10689 |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
| Daniel Veillard | 556c668 | 2001-10-06 09:59:51 +0000 | [diff] [blame] | 10690 | 	    CHECK_ERROR0; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10691 |             if ((ctxt->value != NULL) && | 
 | 10692 |                 (ctxt->value->type == XPATH_NODESET) && | 
 | 10693 |                 (ctxt->value->nodesetval != NULL)) | 
 | 10694 |                 xmlXPathNodeSetSort(ctxt->value->nodesetval); | 
 | 10695 |             return (total); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10696 | #ifdef LIBXML_XPTR_ENABLED | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10697 |         case XPATH_OP_RANGETO:{ | 
 | 10698 |                 xmlXPathObjectPtr range; | 
 | 10699 |                 xmlXPathObjectPtr res, obj; | 
 | 10700 |                 xmlXPathObjectPtr tmp; | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10701 |                 xmlLocationSetPtr newlocset = NULL; | 
 | 10702 | 		    xmlLocationSetPtr oldlocset; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10703 |                 xmlNodeSetPtr oldset; | 
| William M. Brack | 72ee48d | 2003-12-30 08:30:19 +0000 | [diff] [blame] | 10704 |                 int i, j; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10705 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10706 |                 if (op->ch1 != -1) | 
 | 10707 |                     total += | 
 | 10708 |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); | 
 | 10709 |                 if (op->ch2 == -1) | 
 | 10710 |                     return (total); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10711 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10712 |                 if (ctxt->value->type == XPATH_LOCATIONSET) { | 
 | 10713 |                     /* | 
 | 10714 |                      * Extract the old locset, and then evaluate the result of the | 
 | 10715 |                      * expression for all the element in the locset. use it to grow | 
 | 10716 |                      * up a new locset. | 
 | 10717 |                      */ | 
 | 10718 |                     CHECK_TYPE0(XPATH_LOCATIONSET); | 
 | 10719 |                     obj = valuePop(ctxt); | 
 | 10720 |                     oldlocset = obj->user; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10721 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10722 |                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { | 
| William M. Brack | 72ee48d | 2003-12-30 08:30:19 +0000 | [diff] [blame] | 10723 | 		        ctxt->context->node = NULL; | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10724 |                         ctxt->context->contextSize = 0; | 
 | 10725 |                         ctxt->context->proximityPosition = 0; | 
 | 10726 |                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); | 
 | 10727 |                         res = valuePop(ctxt); | 
 | 10728 |                         if (res != NULL) | 
 | 10729 |                             xmlXPathFreeObject(res); | 
 | 10730 |                         valuePush(ctxt, obj); | 
 | 10731 |                         CHECK_ERROR0; | 
 | 10732 |                         return (total); | 
 | 10733 |                     } | 
 | 10734 |                     newlocset = xmlXPtrLocationSetCreate(NULL); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10735 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10736 |                     for (i = 0; i < oldlocset->locNr; i++) { | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10737 |                         /* | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10738 |                          * Run the evaluation with a node list made of a | 
 | 10739 |                          * single item in the nodelocset. | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10740 |                          */ | 
| William M. Brack | f7eb794 | 2003-12-31 07:59:17 +0000 | [diff] [blame] | 10741 |                         ctxt->context->node = oldlocset->locTab[i]->user; | 
 | 10742 |                         ctxt->context->contextSize = oldlocset->locNr; | 
 | 10743 |                         ctxt->context->proximityPosition = i + 1; | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10744 |                         tmp = xmlXPathNewNodeSet(ctxt->context->node); | 
 | 10745 |                         valuePush(ctxt, tmp); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10746 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10747 |                         if (op->ch2 != -1) | 
 | 10748 |                             total += | 
 | 10749 |                                 xmlXPathCompOpEval(ctxt, | 
 | 10750 |                                                    &comp->steps[op->ch2]); | 
 | 10751 |                         CHECK_ERROR0; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10752 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10753 |                         res = valuePop(ctxt); | 
| William M. Brack | 72ee48d | 2003-12-30 08:30:19 +0000 | [diff] [blame] | 10754 | 			if (res->type == XPATH_LOCATIONSET) { | 
 | 10755 | 			    xmlLocationSetPtr rloc =  | 
 | 10756 | 			        (xmlLocationSetPtr)res->user; | 
 | 10757 | 			    for (j=0; j<rloc->locNr; j++) { | 
 | 10758 | 			        range = xmlXPtrNewRange( | 
 | 10759 | 				  oldlocset->locTab[i]->user, | 
 | 10760 | 				  oldlocset->locTab[i]->index, | 
 | 10761 | 				  rloc->locTab[j]->user2, | 
 | 10762 | 				  rloc->locTab[j]->index2); | 
 | 10763 | 				if (range != NULL) { | 
 | 10764 | 				    xmlXPtrLocationSetAdd(newlocset, range); | 
 | 10765 | 				} | 
 | 10766 | 			    } | 
 | 10767 | 			} else { | 
 | 10768 | 			    range = xmlXPtrNewRangeNodeObject( | 
 | 10769 | 				(xmlNodePtr)oldlocset->locTab[i]->user, res); | 
 | 10770 |                             if (range != NULL) { | 
 | 10771 |                                 xmlXPtrLocationSetAdd(newlocset,range); | 
 | 10772 | 			    } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10773 |                         } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10774 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10775 |                         /* | 
 | 10776 |                          * Cleanup | 
 | 10777 |                          */ | 
 | 10778 |                         if (res != NULL) | 
 | 10779 |                             xmlXPathFreeObject(res); | 
 | 10780 |                         if (ctxt->value == tmp) { | 
 | 10781 |                             res = valuePop(ctxt); | 
 | 10782 |                             xmlXPathFreeObject(res); | 
 | 10783 |                         } | 
 | 10784 |  | 
 | 10785 |                         ctxt->context->node = NULL; | 
 | 10786 |                     } | 
| William M. Brack | 72ee48d | 2003-12-30 08:30:19 +0000 | [diff] [blame] | 10787 | 		} else {	/* Not a location set */ | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10788 |                     CHECK_TYPE0(XPATH_NODESET); | 
 | 10789 |                     obj = valuePop(ctxt); | 
 | 10790 |                     oldset = obj->nodesetval; | 
 | 10791 |                     ctxt->context->node = NULL; | 
 | 10792 |  | 
 | 10793 |                     newlocset = xmlXPtrLocationSetCreate(NULL); | 
 | 10794 |  | 
 | 10795 |                     if (oldset != NULL) { | 
 | 10796 |                         for (i = 0; i < oldset->nodeNr; i++) { | 
 | 10797 |                             /* | 
 | 10798 |                              * Run the evaluation with a node list made of a single item | 
 | 10799 |                              * in the nodeset. | 
 | 10800 |                              */ | 
 | 10801 |                             ctxt->context->node = oldset->nodeTab[i]; | 
 | 10802 |                             tmp = xmlXPathNewNodeSet(ctxt->context->node); | 
 | 10803 |                             valuePush(ctxt, tmp); | 
 | 10804 |  | 
 | 10805 |                             if (op->ch2 != -1) | 
 | 10806 |                                 total += | 
 | 10807 |                                     xmlXPathCompOpEval(ctxt, | 
 | 10808 |                                                    &comp->steps[op->ch2]); | 
 | 10809 |                             CHECK_ERROR0; | 
 | 10810 |  | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10811 |                             res = valuePop(ctxt); | 
 | 10812 |                             range = | 
 | 10813 |                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], | 
 | 10814 |                                                       res); | 
 | 10815 |                             if (range != NULL) { | 
 | 10816 |                                 xmlXPtrLocationSetAdd(newlocset, range); | 
 | 10817 |                             } | 
 | 10818 |  | 
 | 10819 |                             /* | 
 | 10820 |                              * Cleanup | 
 | 10821 |                              */ | 
 | 10822 |                             if (res != NULL) | 
 | 10823 |                                 xmlXPathFreeObject(res); | 
 | 10824 |                             if (ctxt->value == tmp) { | 
 | 10825 |                                 res = valuePop(ctxt); | 
 | 10826 |                                 xmlXPathFreeObject(res); | 
 | 10827 |                             } | 
 | 10828 |  | 
 | 10829 |                             ctxt->context->node = NULL; | 
 | 10830 |                         } | 
 | 10831 |                     } | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10832 |                 } | 
 | 10833 |  | 
 | 10834 |                 /* | 
 | 10835 |                  * The result is used as the new evaluation set. | 
 | 10836 |                  */ | 
 | 10837 |                 xmlXPathFreeObject(obj); | 
 | 10838 |                 ctxt->context->node = NULL; | 
 | 10839 |                 ctxt->context->contextSize = -1; | 
 | 10840 |                 ctxt->context->proximityPosition = -1; | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10841 |                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10842 |                 return (total); | 
 | 10843 |             } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10844 | #endif /* LIBXML_XPTR_ENABLED */ | 
 | 10845 |     } | 
 | 10846 |     xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 10847 |                     "XPath: unknown precompiled operation %d\n", op->op); | 
 | 10848 |     return (total); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10849 | } | 
 | 10850 |  | 
 | 10851 | /** | 
 | 10852 |  * xmlXPathRunEval: | 
 | 10853 |  * @ctxt:  the XPath parser context with the compiled expression | 
 | 10854 |  * | 
 | 10855 |  * Evaluate the Precompiled XPath expression in the given context. | 
 | 10856 |  */ | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 10857 | static void | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10858 | xmlXPathRunEval(xmlXPathParserContextPtr ctxt) { | 
 | 10859 |     xmlXPathCompExprPtr comp; | 
 | 10860 |  | 
 | 10861 |     if ((ctxt == NULL) || (ctxt->comp == NULL)) | 
 | 10862 | 	return; | 
 | 10863 |  | 
 | 10864 |     if (ctxt->valueTab == NULL) { | 
 | 10865 | 	/* Allocate the value stack */ | 
 | 10866 | 	ctxt->valueTab = (xmlXPathObjectPtr *)  | 
 | 10867 | 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); | 
 | 10868 | 	if (ctxt->valueTab == NULL) { | 
| Daniel Veillard | d96f6d3 | 2003-10-07 21:25:12 +0000 | [diff] [blame] | 10869 | 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10870 | 	    xmlFree(ctxt); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10871 | 	} | 
 | 10872 | 	ctxt->valueNr = 0; | 
 | 10873 | 	ctxt->valueMax = 10; | 
 | 10874 | 	ctxt->value = NULL; | 
 | 10875 |     } | 
 | 10876 |     comp = ctxt->comp; | 
| Aleksey Sanin | 29b6f76 | 2002-05-05 06:59:57 +0000 | [diff] [blame] | 10877 |     if(comp->last < 0) { | 
 | 10878 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 10879 | 	    "xmlXPathRunEval: last is less than zero\n"); | 
 | 10880 | 	return; | 
 | 10881 |     } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 10882 |     xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); | 
 | 10883 | } | 
 | 10884 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10885 | /************************************************************************ | 
 | 10886 |  *									* | 
 | 10887 |  * 			Public interfaces				* | 
 | 10888 |  *									* | 
 | 10889 |  ************************************************************************/ | 
 | 10890 |  | 
 | 10891 | /** | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 10892 |  * xmlXPathEvalPredicate: | 
 | 10893 |  * @ctxt:  the XPath context | 
 | 10894 |  * @res:  the Predicate Expression evaluation result | 
 | 10895 |  * | 
 | 10896 |  * Evaluate a predicate result for the current node. | 
 | 10897 |  * A PredicateExpr is evaluated by evaluating the Expr and converting | 
 | 10898 |  * the result to a boolean. If the result is a number, the result will | 
 | 10899 |  * be converted to true if the number is equal to the position of the | 
 | 10900 |  * context node in the context node list (as returned by the position | 
 | 10901 |  * function) and will be converted to false otherwise; if the result | 
 | 10902 |  * is not a number, then the result will be converted as if by a call | 
 | 10903 |  * to the boolean function.  | 
 | 10904 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 10905 |  * Returns 1 if predicate is true, 0 otherwise | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 10906 |  */ | 
 | 10907 | int | 
 | 10908 | xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { | 
| Daniel Veillard | ce682bc | 2004-11-05 17:22:25 +0000 | [diff] [blame] | 10909 |     if ((ctxt == NULL) || (res == NULL)) return(0); | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 10910 |     switch (res->type) { | 
 | 10911 |         case XPATH_BOOLEAN: | 
 | 10912 | 	    return(res->boolval); | 
 | 10913 |         case XPATH_NUMBER: | 
 | 10914 | 	    return(res->floatval == ctxt->proximityPosition); | 
 | 10915 |         case XPATH_NODESET: | 
 | 10916 |         case XPATH_XSLT_TREE: | 
| Daniel Veillard | d8df6c0 | 2001-04-05 16:54:14 +0000 | [diff] [blame] | 10917 | 	    if (res->nodesetval == NULL) | 
 | 10918 | 		return(0); | 
| Daniel Veillard | fbf8a2d | 2001-03-19 15:58:54 +0000 | [diff] [blame] | 10919 | 	    return(res->nodesetval->nodeNr != 0); | 
 | 10920 |         case XPATH_STRING: | 
 | 10921 | 	    return((res->stringval != NULL) && | 
 | 10922 | 	           (xmlStrlen(res->stringval) != 0)); | 
 | 10923 |         default: | 
 | 10924 | 	    STRANGE | 
 | 10925 |     } | 
 | 10926 |     return(0); | 
 | 10927 | } | 
 | 10928 |  | 
 | 10929 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10930 |  * xmlXPathEvaluatePredicateResult: | 
 | 10931 |  * @ctxt:  the XPath Parser context | 
 | 10932 |  * @res:  the Predicate Expression evaluation result | 
 | 10933 |  * | 
 | 10934 |  * Evaluate a predicate result for the current node. | 
 | 10935 |  * A PredicateExpr is evaluated by evaluating the Expr and converting | 
 | 10936 |  * the result to a boolean. If the result is a number, the result will | 
 | 10937 |  * be converted to true if the number is equal to the position of the | 
 | 10938 |  * context node in the context node list (as returned by the position | 
 | 10939 |  * function) and will be converted to false otherwise; if the result | 
 | 10940 |  * is not a number, then the result will be converted as if by a call | 
 | 10941 |  * to the boolean function.  | 
 | 10942 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 10943 |  * Returns 1 if predicate is true, 0 otherwise | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10944 |  */ | 
 | 10945 | int | 
 | 10946 | xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,  | 
 | 10947 |                                 xmlXPathObjectPtr res) { | 
| Daniel Veillard | ce682bc | 2004-11-05 17:22:25 +0000 | [diff] [blame] | 10948 |     if ((ctxt == NULL) || (res == NULL)) return(0); | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10949 |     switch (res->type) { | 
 | 10950 |         case XPATH_BOOLEAN: | 
 | 10951 | 	    return(res->boolval); | 
 | 10952 |         case XPATH_NUMBER: | 
| Daniel Veillard | 9ea6231 | 2004-04-29 14:04:09 +0000 | [diff] [blame] | 10953 | #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) | 
| Daniel Veillard | 7c4eb63 | 2004-04-19 21:29:12 +0000 | [diff] [blame] | 10954 | 	    return((res->floatval == ctxt->context->proximityPosition) && | 
 | 10955 | 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ | 
| Daniel Veillard | 2582a33 | 2004-04-18 19:49:46 +0000 | [diff] [blame] | 10956 | #else | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10957 | 	    return(res->floatval == ctxt->context->proximityPosition); | 
| Daniel Veillard | 2582a33 | 2004-04-18 19:49:46 +0000 | [diff] [blame] | 10958 | #endif | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10959 |         case XPATH_NODESET: | 
 | 10960 |         case XPATH_XSLT_TREE: | 
| Daniel Veillard | 73639a7 | 2001-04-10 14:31:39 +0000 | [diff] [blame] | 10961 | 	    if (res->nodesetval == NULL) | 
| Daniel Veillard | 911f49a | 2001-04-07 15:39:35 +0000 | [diff] [blame] | 10962 | 		return(0); | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10963 | 	    return(res->nodesetval->nodeNr != 0); | 
 | 10964 |         case XPATH_STRING: | 
 | 10965 | 	    return((res->stringval != NULL) && | 
 | 10966 | 	           (xmlStrlen(res->stringval) != 0)); | 
| William M. Brack | 0817191 | 2003-12-29 02:52:11 +0000 | [diff] [blame] | 10967 | #ifdef LIBXML_XPTR_ENABLED | 
 | 10968 | 	case XPATH_LOCATIONSET:{ | 
 | 10969 | 	    xmlLocationSetPtr ptr = res->user; | 
 | 10970 | 	    if (ptr == NULL) | 
 | 10971 | 	        return(0); | 
 | 10972 | 	    return (ptr->locNr != 0); | 
 | 10973 | 	    } | 
 | 10974 | #endif | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 10975 |         default: | 
 | 10976 | 	    STRANGE | 
 | 10977 |     } | 
 | 10978 |     return(0); | 
 | 10979 | } | 
 | 10980 |  | 
 | 10981 | /** | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 10982 |  * xmlXPathCtxtCompile: | 
 | 10983 |  * @ctxt: an XPath context | 
 | 10984 |  * @str:  the XPath expression | 
 | 10985 |  * | 
 | 10986 |  * Compile an XPath expression | 
 | 10987 |  * | 
 | 10988 |  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. | 
 | 10989 |  *         the caller has to free the object. | 
 | 10990 |  */ | 
 | 10991 | xmlXPathCompExprPtr | 
 | 10992 | xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { | 
 | 10993 |     xmlXPathParserContextPtr pctxt; | 
 | 10994 |     xmlXPathCompExprPtr comp; | 
 | 10995 |  | 
 | 10996 |     xmlXPathInit(); | 
 | 10997 |  | 
 | 10998 |     pctxt = xmlXPathNewParserContext(str, ctxt); | 
 | 10999 |     xmlXPathCompileExpr(pctxt); | 
 | 11000 |  | 
 | 11001 |     if( pctxt->error != XPATH_EXPRESSION_OK ) | 
 | 11002 |     { | 
 | 11003 |         xmlXPathFreeParserContext(pctxt); | 
 | 11004 |         return (0); | 
 | 11005 |     } | 
 | 11006 |  | 
 | 11007 |     if (*pctxt->cur != 0) { | 
 | 11008 | 	/*  | 
 | 11009 | 	 * aleksey: in some cases this line prints *second* error message | 
 | 11010 | 	 * (see bug #78858) and probably this should be fixed. | 
 | 11011 | 	 * However, we are not sure that all error messages are printed | 
 | 11012 | 	 * out in other places. It's not critical so we leave it as-is for now | 
 | 11013 | 	 */ | 
 | 11014 | 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); | 
 | 11015 | 	comp = NULL; | 
 | 11016 |     } else { | 
 | 11017 | 	comp = pctxt->comp; | 
 | 11018 | 	pctxt->comp = NULL; | 
 | 11019 |     } | 
 | 11020 |     xmlXPathFreeParserContext(pctxt); | 
 | 11021 |     if (comp != NULL) { | 
 | 11022 | 	comp->expr = xmlStrdup(str); | 
 | 11023 | #ifdef DEBUG_EVAL_COUNTS | 
 | 11024 | 	comp->string = xmlStrdup(str); | 
 | 11025 | 	comp->nb = 0; | 
 | 11026 | #endif | 
 | 11027 |     } | 
 | 11028 |     return(comp); | 
 | 11029 | } | 
 | 11030 |  | 
 | 11031 | /** | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 11032 |  * xmlXPathCompile: | 
 | 11033 |  * @str:  the XPath expression | 
 | 11034 |  * | 
 | 11035 |  * Compile an XPath expression | 
 | 11036 |  * | 
| Daniel Veillard | 591b4be | 2003-02-09 23:33:36 +0000 | [diff] [blame] | 11037 |  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 11038 |  *         the caller has to free the object. | 
 | 11039 |  */ | 
 | 11040 | xmlXPathCompExprPtr | 
 | 11041 | xmlXPathCompile(const xmlChar *str) { | 
| Daniel Veillard | 4773df2 | 2004-01-23 13:15:13 +0000 | [diff] [blame] | 11042 |     return(xmlXPathCtxtCompile(NULL, str)); | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 11043 | } | 
 | 11044 |  | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11045 | /** | 
 | 11046 |  * xmlXPathCompiledEval: | 
 | 11047 |  * @comp:  the compiled XPath expression | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11048 |  * @ctx:  the XPath context | 
 | 11049 |  * | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11050 |  * Evaluate the Precompiled XPath expression in the given context. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11051 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 11052 |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11053 |  *         the caller has to free the object. | 
 | 11054 |  */ | 
 | 11055 | xmlXPathObjectPtr | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11056 | xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) { | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11057 |     xmlXPathParserContextPtr ctxt; | 
 | 11058 |     xmlXPathObjectPtr res, tmp, init = NULL; | 
 | 11059 |     int stack = 0; | 
| Daniel Veillard | 8146394 | 2001-10-16 12:34:39 +0000 | [diff] [blame] | 11060 | #ifndef LIBXML_THREAD_ENABLED | 
 | 11061 |     static int reentance = 0; | 
 | 11062 | #endif | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11063 |  | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11064 |     if ((comp == NULL) || (ctx == NULL)) | 
 | 11065 | 	return(NULL); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11066 |     xmlXPathInit(); | 
 | 11067 |  | 
 | 11068 |     CHECK_CONTEXT(ctx) | 
 | 11069 |  | 
| Daniel Veillard | 8146394 | 2001-10-16 12:34:39 +0000 | [diff] [blame] | 11070 | #ifndef LIBXML_THREAD_ENABLED | 
 | 11071 |     reentance++; | 
 | 11072 |     if (reentance > 1) | 
 | 11073 | 	xmlXPathDisableOptimizer = 1; | 
 | 11074 | #endif | 
 | 11075 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 11076 | #ifdef DEBUG_EVAL_COUNTS | 
 | 11077 |     comp->nb++; | 
 | 11078 |     if ((comp->string != NULL) && (comp->nb > 100)) { | 
 | 11079 | 	fprintf(stderr, "100 x %s\n", comp->string); | 
 | 11080 | 	comp->nb = 0; | 
 | 11081 |     } | 
 | 11082 | #endif | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11083 |     ctxt = xmlXPathCompParserContext(comp, ctx); | 
 | 11084 |     xmlXPathRunEval(ctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11085 |  | 
 | 11086 |     if (ctxt->value == NULL) { | 
 | 11087 | 	xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 11088 | 		"xmlXPathCompiledEval: evaluation failed\n"); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11089 | 	res = NULL; | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11090 |     } else { | 
 | 11091 | 	res = valuePop(ctxt); | 
 | 11092 |     } | 
 | 11093 |  | 
| Daniel Veillard | f06307e | 2001-07-03 10:35:50 +0000 | [diff] [blame] | 11094 |      | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11095 |     do { | 
 | 11096 |         tmp = valuePop(ctxt); | 
 | 11097 | 	if (tmp != NULL) { | 
 | 11098 | 	    if (tmp != init) | 
 | 11099 | 		stack++;     | 
 | 11100 | 	    xmlXPathFreeObject(tmp); | 
 | 11101 |         } | 
 | 11102 |     } while (tmp != NULL); | 
 | 11103 |     if ((stack != 0) && (res != NULL)) { | 
 | 11104 | 	xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 11105 | 		"xmlXPathCompiledEval: %d object left on the stack\n", | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11106 | 	        stack); | 
 | 11107 |     } | 
 | 11108 |     if (ctxt->error != XPATH_EXPRESSION_OK) { | 
 | 11109 | 	xmlXPathFreeObject(res); | 
 | 11110 | 	res = NULL; | 
 | 11111 |     } | 
 | 11112 |          | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11113 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 11114 |     ctxt->comp = NULL; | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11115 |     xmlXPathFreeParserContext(ctxt); | 
| Daniel Veillard | 8146394 | 2001-10-16 12:34:39 +0000 | [diff] [blame] | 11116 | #ifndef LIBXML_THREAD_ENABLED | 
 | 11117 |     reentance--; | 
 | 11118 | #endif | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11119 |     return(res); | 
 | 11120 | } | 
 | 11121 |  | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 11122 | /** | 
 | 11123 |  * xmlXPathEvalExpr: | 
 | 11124 |  * @ctxt:  the XPath Parser context | 
 | 11125 |  * | 
 | 11126 |  * Parse and evaluate an XPath expression in the given context, | 
 | 11127 |  * then push the result on the context stack | 
 | 11128 |  */ | 
 | 11129 | void | 
 | 11130 | xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { | 
 | 11131 |     xmlXPathCompileExpr(ctxt); | 
| Aleksey Sanin | 50fe8b1 | 2002-05-07 16:21:36 +0000 | [diff] [blame] | 11132 |     CHECK_ERROR; | 
| Daniel Veillard | afcbe1c | 2001-03-19 10:57:13 +0000 | [diff] [blame] | 11133 |     xmlXPathRunEval(ctxt); | 
 | 11134 | } | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11135 |  | 
 | 11136 | /** | 
 | 11137 |  * xmlXPathEval: | 
 | 11138 |  * @str:  the XPath expression | 
 | 11139 |  * @ctx:  the XPath context | 
 | 11140 |  * | 
 | 11141 |  * Evaluate the XPath Location Path in the given context. | 
 | 11142 |  * | 
| Daniel Veillard | cbaf399 | 2001-12-31 16:16:02 +0000 | [diff] [blame] | 11143 |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11144 |  *         the caller has to free the object. | 
 | 11145 |  */ | 
 | 11146 | xmlXPathObjectPtr | 
 | 11147 | xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { | 
 | 11148 |     xmlXPathParserContextPtr ctxt; | 
 | 11149 |     xmlXPathObjectPtr res, tmp, init = NULL; | 
 | 11150 |     int stack = 0; | 
 | 11151 |  | 
 | 11152 |     xmlXPathInit(); | 
 | 11153 |  | 
 | 11154 |     CHECK_CONTEXT(ctx) | 
 | 11155 |  | 
 | 11156 |     ctxt = xmlXPathNewParserContext(str, ctx); | 
 | 11157 |     xmlXPathEvalExpr(ctxt); | 
| Daniel Veillard | 9e7160d | 2001-03-18 23:17:47 +0000 | [diff] [blame] | 11158 |  | 
 | 11159 |     if (ctxt->value == NULL) { | 
 | 11160 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 11161 | 		"xmlXPathEval: evaluation failed\n"); | 
 | 11162 | 	res = NULL; | 
 | 11163 |     } else if (*ctxt->cur != 0) { | 
 | 11164 | 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); | 
 | 11165 | 	res = NULL; | 
 | 11166 |     } else { | 
 | 11167 | 	res = valuePop(ctxt); | 
 | 11168 |     } | 
 | 11169 |  | 
 | 11170 |     do { | 
 | 11171 |         tmp = valuePop(ctxt); | 
 | 11172 | 	if (tmp != NULL) { | 
 | 11173 | 	    if (tmp != init) | 
 | 11174 | 		stack++;     | 
 | 11175 | 	    xmlXPathFreeObject(tmp); | 
 | 11176 |         } | 
 | 11177 |     } while (tmp != NULL); | 
 | 11178 |     if ((stack != 0) && (res != NULL)) { | 
 | 11179 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 11180 | 		"xmlXPathEval: %d object left on the stack\n", | 
 | 11181 | 	        stack); | 
 | 11182 |     } | 
 | 11183 |     if (ctxt->error != XPATH_EXPRESSION_OK) { | 
 | 11184 | 	xmlXPathFreeObject(res); | 
 | 11185 | 	res = NULL; | 
 | 11186 |     } | 
 | 11187 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11188 |     xmlXPathFreeParserContext(ctxt); | 
 | 11189 |     return(res); | 
 | 11190 | } | 
 | 11191 |  | 
 | 11192 | /** | 
 | 11193 |  * xmlXPathEvalExpression: | 
 | 11194 |  * @str:  the XPath expression | 
 | 11195 |  * @ctxt:  the XPath context | 
 | 11196 |  * | 
 | 11197 |  * Evaluate the XPath expression in the given context. | 
 | 11198 |  * | 
 | 11199 |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. | 
 | 11200 |  *         the caller has to free the object. | 
 | 11201 |  */ | 
 | 11202 | xmlXPathObjectPtr | 
 | 11203 | xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { | 
 | 11204 |     xmlXPathParserContextPtr pctxt; | 
 | 11205 |     xmlXPathObjectPtr res, tmp; | 
 | 11206 |     int stack = 0; | 
 | 11207 |  | 
 | 11208 |     xmlXPathInit(); | 
 | 11209 |  | 
 | 11210 |     CHECK_CONTEXT(ctxt) | 
 | 11211 |  | 
 | 11212 |     pctxt = xmlXPathNewParserContext(str, ctxt); | 
 | 11213 |     xmlXPathEvalExpr(pctxt); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11214 |  | 
 | 11215 |     if (*pctxt->cur != 0) { | 
 | 11216 | 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); | 
 | 11217 | 	res = NULL; | 
 | 11218 |     } else { | 
 | 11219 | 	res = valuePop(pctxt); | 
 | 11220 |     } | 
 | 11221 |     do { | 
 | 11222 |         tmp = valuePop(pctxt); | 
 | 11223 | 	if (tmp != NULL) { | 
 | 11224 | 	    xmlXPathFreeObject(tmp); | 
 | 11225 | 	    stack++; | 
 | 11226 | 	} | 
 | 11227 |     } while (tmp != NULL); | 
 | 11228 |     if ((stack != 0) && (res != NULL)) { | 
 | 11229 | 	xmlGenericError(xmlGenericErrorContext, | 
 | 11230 | 		"xmlXPathEvalExpression: %d object left on the stack\n", | 
 | 11231 | 	        stack); | 
 | 11232 |     } | 
 | 11233 |     xmlXPathFreeParserContext(pctxt); | 
 | 11234 |     return(res); | 
 | 11235 | } | 
 | 11236 |  | 
| Daniel Veillard | 42766c0 | 2002-08-22 20:52:17 +0000 | [diff] [blame] | 11237 | /************************************************************************ | 
 | 11238 |  *									* | 
 | 11239 |  *	Extra functions not pertaining to the XPath spec		* | 
 | 11240 |  *									* | 
 | 11241 |  ************************************************************************/ | 
 | 11242 | /** | 
 | 11243 |  * xmlXPathEscapeUriFunction: | 
 | 11244 |  * @ctxt:  the XPath Parser context | 
 | 11245 |  * @nargs:  the number of arguments | 
 | 11246 |  * | 
 | 11247 |  * Implement the escape-uri() XPath function | 
 | 11248 |  *    string escape-uri(string $str, bool $escape-reserved) | 
 | 11249 |  * | 
 | 11250 |  * This function applies the URI escaping rules defined in section 2 of [RFC | 
 | 11251 |  * 2396] to the string supplied as $uri-part, which typically represents all | 
 | 11252 |  * or part of a URI. The effect of the function is to replace any special | 
 | 11253 |  * character in the string by an escape sequence of the form %xx%yy..., | 
 | 11254 |  * where xxyy... is the hexadecimal representation of the octets used to | 
 | 11255 |  * represent the character in UTF-8. | 
 | 11256 |  * | 
 | 11257 |  * The set of characters that are escaped depends on the setting of the | 
 | 11258 |  * boolean argument $escape-reserved. | 
 | 11259 |  * | 
 | 11260 |  * If $escape-reserved is true, all characters are escaped other than lower | 
 | 11261 |  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters | 
 | 11262 |  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" | 
 | 11263 |  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only | 
 | 11264 |  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and | 
 | 11265 |  * A-F). | 
 | 11266 |  * | 
 | 11267 |  * If $escape-reserved is false, the behavior differs in that characters | 
 | 11268 |  * referred to in [RFC 2396] as reserved characters are not escaped. These | 
 | 11269 |  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". | 
 | 11270 |  *  | 
 | 11271 |  * [RFC 2396] does not define whether escaped URIs should use lower case or | 
 | 11272 |  * upper case for hexadecimal digits. To ensure that escaped URIs can be | 
 | 11273 |  * compared using string comparison functions, this function must always use | 
 | 11274 |  * the upper-case letters A-F. | 
 | 11275 |  *  | 
 | 11276 |  * Generally, $escape-reserved should be set to true when escaping a string | 
 | 11277 |  * that is to form a single part of a URI, and to false when escaping an | 
 | 11278 |  * entire URI or URI reference. | 
 | 11279 |  *  | 
 | 11280 |  * In the case of non-ascii characters, the string is encoded according to  | 
 | 11281 |  * utf-8 and then converted according to RFC 2396. | 
 | 11282 |  * | 
 | 11283 |  * Examples | 
 | 11284 |  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())  | 
 | 11285 |  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" | 
 | 11286 |  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) | 
 | 11287 |  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" | 
 | 11288 |  * | 
 | 11289 |  */ | 
| Daniel Veillard | 118aed7 | 2002-09-24 14:13:13 +0000 | [diff] [blame] | 11290 | static void | 
| Daniel Veillard | 42766c0 | 2002-08-22 20:52:17 +0000 | [diff] [blame] | 11291 | xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
 | 11292 |     xmlXPathObjectPtr str; | 
 | 11293 |     int escape_reserved; | 
 | 11294 |     xmlBufferPtr target; | 
 | 11295 |     xmlChar *cptr; | 
 | 11296 |     xmlChar escape[4]; | 
 | 11297 |      | 
 | 11298 |     CHECK_ARITY(2); | 
 | 11299 |      | 
 | 11300 |     escape_reserved = xmlXPathPopBoolean(ctxt); | 
 | 11301 |      | 
 | 11302 |     CAST_TO_STRING; | 
 | 11303 |     str = valuePop(ctxt); | 
 | 11304 |      | 
 | 11305 |     target = xmlBufferCreate(); | 
 | 11306 |      | 
 | 11307 |     escape[0] = '%'; | 
 | 11308 |     escape[3] = 0; | 
 | 11309 |      | 
 | 11310 |     if (target) { | 
 | 11311 | 	for (cptr = str->stringval; *cptr; cptr++) { | 
 | 11312 | 	    if ((*cptr >= 'A' && *cptr <= 'Z') || | 
 | 11313 | 		(*cptr >= 'a' && *cptr <= 'z') || | 
 | 11314 | 		(*cptr >= '0' && *cptr <= '9') || | 
 | 11315 | 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||  | 
 | 11316 | 		*cptr == '!' || *cptr == '~' || *cptr == '*' || | 
 | 11317 | 		*cptr == '\''|| *cptr == '(' || *cptr == ')' || | 
 | 11318 | 		(*cptr == '%' &&  | 
 | 11319 | 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') || | 
 | 11320 | 		  (cptr[1] >= 'a' && cptr[1] <= 'f') || | 
 | 11321 | 		  (cptr[1] >= '0' && cptr[1] <= '9')) && | 
 | 11322 | 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') || | 
 | 11323 | 		  (cptr[2] >= 'a' && cptr[2] <= 'f') || | 
 | 11324 | 		  (cptr[2] >= '0' && cptr[2] <= '9'))) || | 
 | 11325 | 		(!escape_reserved && | 
 | 11326 | 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' || | 
 | 11327 | 		  *cptr == ':' || *cptr == '@' || *cptr == '&' || | 
 | 11328 | 		  *cptr == '=' || *cptr == '+' || *cptr == '$' || | 
 | 11329 | 		  *cptr == ','))) { | 
 | 11330 | 		xmlBufferAdd(target, cptr, 1); | 
 | 11331 | 	    } else { | 
 | 11332 | 		if ((*cptr >> 4) < 10) | 
 | 11333 | 		    escape[1] = '0' + (*cptr >> 4); | 
 | 11334 | 		else | 
 | 11335 | 		    escape[1] = 'A' - 10 + (*cptr >> 4); | 
 | 11336 | 		if ((*cptr & 0xF) < 10) | 
 | 11337 | 		    escape[2] = '0' + (*cptr & 0xF); | 
 | 11338 | 		else | 
 | 11339 | 		    escape[2] = 'A' - 10 + (*cptr & 0xF); | 
 | 11340 | 		 | 
 | 11341 | 		xmlBufferAdd(target, &escape[0], 3); | 
 | 11342 | 	    } | 
 | 11343 | 	} | 
 | 11344 |     } | 
 | 11345 |     valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); | 
 | 11346 |     xmlBufferFree(target); | 
 | 11347 |     xmlXPathFreeObject(str); | 
 | 11348 | } | 
 | 11349 |  | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11350 | /** | 
 | 11351 |  * xmlXPathRegisterAllFunctions: | 
 | 11352 |  * @ctxt:  the XPath context | 
 | 11353 |  * | 
 | 11354 |  * Registers all default XPath functions in this context | 
 | 11355 |  */ | 
 | 11356 | void | 
 | 11357 | xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) | 
 | 11358 | { | 
 | 11359 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", | 
 | 11360 |                          xmlXPathBooleanFunction); | 
 | 11361 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", | 
 | 11362 |                          xmlXPathCeilingFunction); | 
 | 11363 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", | 
 | 11364 |                          xmlXPathCountFunction); | 
 | 11365 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", | 
 | 11366 |                          xmlXPathConcatFunction); | 
 | 11367 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", | 
 | 11368 |                          xmlXPathContainsFunction); | 
 | 11369 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", | 
 | 11370 |                          xmlXPathIdFunction); | 
 | 11371 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", | 
 | 11372 |                          xmlXPathFalseFunction); | 
 | 11373 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", | 
 | 11374 |                          xmlXPathFloorFunction); | 
 | 11375 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", | 
 | 11376 |                          xmlXPathLastFunction); | 
 | 11377 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", | 
 | 11378 |                          xmlXPathLangFunction); | 
 | 11379 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", | 
 | 11380 |                          xmlXPathLocalNameFunction); | 
 | 11381 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", | 
 | 11382 |                          xmlXPathNotFunction); | 
 | 11383 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", | 
 | 11384 |                          xmlXPathNameFunction); | 
 | 11385 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", | 
 | 11386 |                          xmlXPathNamespaceURIFunction); | 
 | 11387 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", | 
 | 11388 |                          xmlXPathNormalizeFunction); | 
 | 11389 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", | 
 | 11390 |                          xmlXPathNumberFunction); | 
 | 11391 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", | 
 | 11392 |                          xmlXPathPositionFunction); | 
 | 11393 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", | 
 | 11394 |                          xmlXPathRoundFunction); | 
 | 11395 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", | 
 | 11396 |                          xmlXPathStringFunction); | 
 | 11397 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", | 
 | 11398 |                          xmlXPathStringLengthFunction); | 
 | 11399 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", | 
 | 11400 |                          xmlXPathStartsWithFunction); | 
 | 11401 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", | 
 | 11402 |                          xmlXPathSubstringFunction); | 
 | 11403 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", | 
 | 11404 |                          xmlXPathSubstringBeforeFunction); | 
 | 11405 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", | 
 | 11406 |                          xmlXPathSubstringAfterFunction); | 
 | 11407 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", | 
 | 11408 |                          xmlXPathSumFunction); | 
 | 11409 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", | 
 | 11410 |                          xmlXPathTrueFunction); | 
 | 11411 |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", | 
 | 11412 |                          xmlXPathTranslateFunction); | 
| Daniel Veillard | 42766c0 | 2002-08-22 20:52:17 +0000 | [diff] [blame] | 11413 |  | 
 | 11414 |     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", | 
 | 11415 | 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", | 
 | 11416 |                          xmlXPathEscapeUriFunction); | 
| Owen Taylor | 3473f88 | 2001-02-23 17:55:21 +0000 | [diff] [blame] | 11417 | } | 
 | 11418 |  | 
 | 11419 | #endif /* LIBXML_XPATH_ENABLED */ |