blob: 29917117dbf0ac8c9fd98eefde8f9a9855eb8095 [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
Daniel Veillard55b91f22000-10-05 16:30:11 +00004 * designed to be used by both XSLT and XPointer
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
Daniel Veillard1566d3a1999-07-15 14:24:29 +00008 * Public reference:
Daniel Veillard55b91f22000-10-05 16:30:11 +00009 * http://www.w3.org/TR/xpath
Daniel Veillard1566d3a1999-07-15 14:24:29 +000010 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#else
19#include "config.h"
20#endif
21
Daniel Veillardb71379b2000-10-09 12:30:39 +000022#include <libxml/xmlversion.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000023#ifdef LIBXML_XPATH_ENABLED
24
Daniel Veillard7f7d1111999-09-22 09:46:25 +000025#include <stdio.h>
26#include <string.h>
27
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000031#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000032#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000033#endif
34#ifdef HAVE_MATH_H
35#include <float.h>
36#endif
37#ifdef HAVE_IEEEFP_H
38#include <ieeefp.h>
39#endif
40#ifdef HAVE_NAN_H
41#include <nan.h>
42#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000043#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000044#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000045#endif
46
Daniel Veillard361d8452000-04-03 19:48:13 +000047#include <libxml/xmlmemory.h>
48#include <libxml/tree.h>
49#include <libxml/valid.h>
50#include <libxml/xpath.h>
Daniel Veillard29a11cc2000-10-25 13:32:39 +000051#include <libxml/xpathInternals.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000052#include <libxml/parserInternals.h>
Daniel Veillard52afe802000-10-22 16:56:02 +000053#include <libxml/hash.h>
Daniel Veillardac260302000-10-04 13:33:43 +000054#ifdef LIBXML_XPTR_ENABLED
55#include <libxml/xpointer.h>
56#endif
Daniel Veillardc2df4cd2000-10-12 23:15:24 +000057#ifdef LIBXML_DEBUG_ENABLED
58#include <libxml/debugXML.h>
59#endif
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000060#include <libxml/xmlerror.h>
Daniel Veillard1566d3a1999-07-15 14:24:29 +000061
Daniel Veillarddbfd6411999-12-28 16:35:14 +000062/* #define DEBUG */
63/* #define DEBUG_STEP */
64/* #define DEBUG_EXPR */
65
Daniel Veillardc2df4cd2000-10-12 23:15:24 +000066void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
67double xmlXPathStringEvalNumber(const xmlChar *str);
68
Daniel Veillard1566d3a1999-07-15 14:24:29 +000069/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000070 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000071 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000072 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000073double xmlXPathNAN = 0;
74double xmlXPathPINF = 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +000075double xmlXPathNINF = -1;
Daniel Veillarde2d034d1999-07-27 19:52:06 +000076
Daniel Veillardb05deb71999-08-10 19:04:08 +000077#ifndef isinf
78#ifndef HAVE_ISINF
79
80#if HAVE_FPCLASS
81
82int isinf(double d) {
83 fpclass_t type = fpclass(d);
84 switch (type) {
85 case FP_NINF:
86 return(-1);
87 case FP_PINF:
88 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000089 }
90 return(0);
91}
92
93#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
94
95#if HAVE_FP_CLASS_H
96#include <fp_class.h>
97#endif
98
99int isinf(double d) {
100#if HAVE_FP_CLASS
101 int fpclass = fp_class(d);
102#else
103 int fpclass = fp_class_d(d);
104#endif
105 if (fpclass == FP_POS_INF)
106 return(1);
107 if (fpclass == FP_NEG_INF)
108 return(-1);
109 return(0);
110}
111
112#elif defined(HAVE_CLASS)
113
114int isinf(double d) {
115 int fpclass = class(d);
116 if (fpclass == FP_PLUS_INF)
117 return(1);
118 if (fpclass == FP_MINUS_INF)
119 return(-1);
120 return(0);
121}
122#elif defined(finite) || defined(HAVE_FINITE)
123int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000124#elif defined(HUGE_VAL)
Daniel Veillardfc708e22000-04-08 13:17:27 +0000125int isinf(double x)
Daniel Veillard991e63d1999-08-15 23:32:28 +0000126{
127 if (x == HUGE_VAL)
128 return(1);
129 if (x == -HUGE_VAL)
130 return(-1);
131 return(0);
132}
133#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000134
135#endif /* ! HAVE_ISINF */
136#endif /* ! defined(isinf) */
137
138#ifndef isnan
139#ifndef HAVE_ISNAN
140
141#ifdef HAVE_ISNAND
142#define isnan(f) isnand(f)
143#endif /* HAVE_iSNAND */
144
145#endif /* ! HAVE_iSNAN */
146#endif /* ! defined(isnan) */
147
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000148/**
149 * xmlXPathInit:
150 *
151 * Initialize the XPath environment
152 */
153void
154xmlXPathInit(void) {
155 static int initialized = 0;
156
157 if (initialized) return;
158
159 xmlXPathNAN = 0;
160 xmlXPathNAN /= 0;
161
162 xmlXPathPINF = 1;
163 xmlXPathPINF /= 0;
164
Daniel Veillardf6bf9212000-10-26 14:07:44 +0000165 xmlXPathNINF = -1;
166 xmlXPathNINF /= 0;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000167
168 initialized = 1;
169}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000170
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000171/************************************************************************
172 * *
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000173 * Debugging related functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000174 * *
175 ************************************************************************/
176
Daniel Veillard7e99c632000-10-06 12:59:53 +0000177#define TODO \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000178 xmlGenericError(xmlGenericErrorContext, \
179 "Unimplemented block at %s:%d\n", \
Daniel Veillard7e99c632000-10-06 12:59:53 +0000180 __FILE__, __LINE__);
181
182#define STRANGE \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000183 xmlGenericError(xmlGenericErrorContext, \
184 "Internal error at %s:%d\n", \
Daniel Veillard7e99c632000-10-06 12:59:53 +0000185 __FILE__, __LINE__);
186
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000187#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000188void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
189 int i;
190 char shift[100];
191
192 for (i = 0;((i < depth) && (i < 25));i++)
193 shift[2 * i] = shift[2 * i + 1] = ' ';
194 shift[2 * i] = shift[2 * i + 1] = 0;
195 if (cur == NULL) {
196 fprintf(output, shift);
197 fprintf(output, "Node is NULL !\n");
198 return;
199
200 }
201
202 if ((cur->type == XML_DOCUMENT_NODE) ||
203 (cur->type == XML_HTML_DOCUMENT_NODE)) {
204 fprintf(output, shift);
205 fprintf(output, " /\n");
206 } else if (cur->type == XML_ATTRIBUTE_NODE)
207 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
208 else
209 xmlDebugDumpOneNode(output, cur, depth);
210}
211
212void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
213 int i;
214 char shift[100];
215
216 for (i = 0;((i < depth) && (i < 25));i++)
217 shift[2 * i] = shift[2 * i + 1] = ' ';
218 shift[2 * i] = shift[2 * i + 1] = 0;
219
220 if (cur == NULL) {
221 fprintf(output, shift);
222 fprintf(output, "NodeSet is NULL !\n");
223 return;
224
225 }
226
227 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
228 for (i = 0;i < cur->nodeNr;i++) {
229 fprintf(output, shift);
230 fprintf(output, "%d", i + 1);
231 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
232 }
233}
234
235#if defined(LIBXML_XPTR_ENABLED)
236void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
237void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
238 int i;
239 char shift[100];
240
241 for (i = 0;((i < depth) && (i < 25));i++)
242 shift[2 * i] = shift[2 * i + 1] = ' ';
243 shift[2 * i] = shift[2 * i + 1] = 0;
244
245 if (cur == NULL) {
246 fprintf(output, shift);
247 fprintf(output, "LocationSet is NULL !\n");
248 return;
249
250 }
251
252 for (i = 0;i < cur->locNr;i++) {
253 fprintf(output, shift);
254 fprintf(output, "%d : ", i + 1);
255 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
256 }
257}
258#endif
259
260void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
261 int i;
262 char shift[100];
263
264 for (i = 0;((i < depth) && (i < 25));i++)
265 shift[2 * i] = shift[2 * i + 1] = ' ';
266 shift[2 * i] = shift[2 * i + 1] = 0;
267
268 fprintf(output, shift);
269
270 if (cur == NULL) {
271 fprintf(output, "Object is empty (NULL)\n");
272 return;
273 }
274 switch(cur->type) {
275 case XPATH_UNDEFINED:
276 fprintf(output, "Object is uninitialized\n");
277 break;
278 case XPATH_NODESET:
279 fprintf(output, "Object is a Node Set :\n");
280 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
281 break;
282 case XPATH_BOOLEAN:
283 fprintf(output, "Object is a Boolean : ");
284 if (cur->boolval) fprintf(output, "true\n");
285 else fprintf(output, "false\n");
286 break;
287 case XPATH_NUMBER:
288 fprintf(output, "Object is a number : %0g\n", cur->floatval);
289 break;
290 case XPATH_STRING:
291 fprintf(output, "Object is a string : ");
292 xmlDebugDumpString(output, cur->stringval);
293 fprintf(output, "\n");
294 break;
295 case XPATH_POINT:
296 fprintf(output, "Object is a point : index %d in node", cur->index);
297 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
298 fprintf(output, "\n");
299 break;
300 case XPATH_RANGE:
301 if ((cur->user2 == NULL) ||
302 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
303 fprintf(output, "Object is a collapsed range :\n");
304 fprintf(output, shift);
305 if (cur->index >= 0)
306 fprintf(output, "index %d in ", cur->index);
307 fprintf(output, "node\n");
308 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
309 depth + 1);
310 } else {
311 fprintf(output, "Object is a range :\n");
312 fprintf(output, shift);
313 fprintf(output, "From ");
314 if (cur->index >= 0)
315 fprintf(output, "index %d in ", cur->index);
316 fprintf(output, "node\n");
317 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
318 depth + 1);
319 fprintf(output, shift);
320 fprintf(output, "To ");
321 if (cur->index2 >= 0)
322 fprintf(output, "index %d in ", cur->index2);
323 fprintf(output, "node\n");
324 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
325 depth + 1);
326 fprintf(output, "\n");
327 }
328 break;
329 case XPATH_LOCATIONSET:
330#if defined(LIBXML_XPTR_ENABLED)
331 fprintf(output, "Object is a Location Set:\n");
332 xmlXPathDebugDumpLocationSet(output,
333 (xmlLocationSetPtr) cur->user, depth);
334#endif
335 break;
336 case XPATH_USERS:
337 fprintf(output, "Object is user defined\n");
338 break;
339 }
340}
341#endif
342
343/************************************************************************
344 * *
345 * Parser stacks related functions and macros *
346 * *
347 ************************************************************************/
348
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000349/*
350 * Generic function for accessing stacks in the Parser Context
351 */
352
353#define PUSH_AND_POP(type, name) \
354extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
355 if (ctxt->name##Nr >= ctxt->name##Max) { \
356 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000357 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000358 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
359 if (ctxt->name##Tab == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000360 xmlGenericError(xmlGenericErrorContext, \
361 "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000362 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000363 } \
364 } \
365 ctxt->name##Tab[ctxt->name##Nr] = value; \
366 ctxt->name = value; \
367 return(ctxt->name##Nr++); \
368} \
369extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
370 type ret; \
371 if (ctxt->name##Nr <= 0) return(0); \
372 ctxt->name##Nr--; \
373 if (ctxt->name##Nr > 0) \
374 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
375 else \
376 ctxt->name = NULL; \
377 ret = ctxt->name##Tab[ctxt->name##Nr]; \
378 ctxt->name##Tab[ctxt->name##Nr] = 0; \
379 return(ret); \
380} \
381
382PUSH_AND_POP(xmlXPathObjectPtr, value)
383
384/*
385 * Macros for accessing the content. Those should be used only by the parser,
386 * and not exported.
387 *
388 * Dirty macros, i.e. one need to make assumption on the context to use them
389 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000390 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000391 * CUR returns the current xmlChar value, i.e. a 8 bit value
392 * in ISO-Latin or UTF-8.
393 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000394 * only to compare to ASCII values otherwise it would break when
395 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000396 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000397 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000398 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000399 * strings within the parser.
400 * CURRENT Returns the current char value, with the full decoding of
401 * UTF-8 if we are using this mode. It returns an int.
402 * NEXT Skip to the next character, this does the proper decoding
403 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000404 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000405 */
406
407#define CUR (*ctxt->cur)
408#define SKIP(val) ctxt->cur += (val)
409#define NXT(val) ctxt->cur[(val)]
410#define CUR_PTR ctxt->cur
411
412#define SKIP_BLANKS \
413 while (IS_BLANK(*(ctxt->cur))) NEXT
414
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000415#define CURRENT (*ctxt->cur)
416#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000417
418/************************************************************************
419 * *
420 * Error handling routines *
421 * *
422 ************************************************************************/
423
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000424
425const char *xmlXPathErrorMessages[] = {
426 "Ok",
427 "Number encoding",
428 "Unfinished litteral",
429 "Start of litteral",
430 "Expected $ for variable reference",
431 "Undefined variable",
432 "Invalid predicate",
433 "Invalid expression",
434 "Missing closing curly brace",
435 "Unregistered function",
436 "Invalid operand",
437 "Invalid type",
438 "Invalid number of arguments",
Daniel Veillardf09e7e32000-10-01 15:53:30 +0000439 "Invalid context size",
440 "Invalid context position",
Daniel Veillardb71379b2000-10-09 12:30:39 +0000441 "Memory allocation error",
442 "Syntax error",
443 "Resource error",
444 "Sub resource error"
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000445};
446
447/**
448 * xmlXPathError:
449 * @ctxt: the XPath Parser context
450 * @file: the file name
451 * @line: the line number
452 * @no: the error number
453 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000454 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000455 *
456 * Returns the newly created object.
457 */
458void
459xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
460 int line, int no) {
461 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000462 const xmlChar *cur;
463 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000464
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000465 xmlGenericError(xmlGenericErrorContext,
466 "Error %s:%d: %s\n", file, line,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000467 xmlXPathErrorMessages[no]);
468
469 cur = ctxt->cur;
470 base = ctxt->base;
471 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
472 cur--;
473 }
474 n = 0;
475 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
476 cur--;
477 if ((*cur == '\n') || (*cur == '\r')) cur++;
478 base = cur;
479 n = 0;
480 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000481 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000482 n++;
483 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000484 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000485 cur = ctxt->cur;
486 while ((*cur == '\n') || (*cur == '\r'))
487 cur--;
488 n = 0;
489 while ((cur != base) && (n++ < 80)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000490 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000491 base++;
492 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000493 xmlGenericError(xmlGenericErrorContext,"^\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000494}
495
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000496
497/************************************************************************
498 * *
499 * Routines to handle NodeSets *
500 * *
501 ************************************************************************/
502
503#define XML_NODESET_DEFAULT 10
504/**
505 * xmlXPathNodeSetCreate:
506 * @val: an initial xmlNodePtr, or NULL
507 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000508 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000509 *
510 * Returns the newly created object.
511 */
512xmlNodeSetPtr
513xmlXPathNodeSetCreate(xmlNodePtr val) {
514 xmlNodeSetPtr ret;
515
Daniel Veillard6454aec1999-09-02 22:04:43 +0000516 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000517 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000518 xmlGenericError(xmlGenericErrorContext,
519 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000520 return(NULL);
521 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000522 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000523 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000524 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000525 sizeof(xmlNodePtr));
526 if (ret->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000527 xmlGenericError(xmlGenericErrorContext,
528 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000529 return(NULL);
530 }
531 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000532 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000533 ret->nodeMax = XML_NODESET_DEFAULT;
534 ret->nodeTab[ret->nodeNr++] = val;
535 }
536 return(ret);
537}
538
539/**
540 * xmlXPathNodeSetAdd:
541 * @cur: the initial node set
542 * @val: a new xmlNodePtr
543 *
544 * add a new xmlNodePtr ot an existing NodeSet
545 */
546void
547xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
548 int i;
549
550 if (val == NULL) return;
551
552 /*
553 * check against doublons
554 */
555 for (i = 0;i < cur->nodeNr;i++)
556 if (cur->nodeTab[i] == val) return;
557
558 /*
559 * grow the nodeTab if needed
560 */
561 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000562 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000563 sizeof(xmlNodePtr));
564 if (cur->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000565 xmlGenericError(xmlGenericErrorContext,
566 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000567 return;
568 }
569 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000570 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000571 cur->nodeMax = XML_NODESET_DEFAULT;
572 } else if (cur->nodeNr == cur->nodeMax) {
573 xmlNodePtr *temp;
574
575 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000576 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000577 sizeof(xmlNodePtr));
578 if (temp == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000579 xmlGenericError(xmlGenericErrorContext,
580 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000581 return;
582 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000583 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000584 }
585 cur->nodeTab[cur->nodeNr++] = val;
586}
587
588/**
589 * xmlXPathNodeSetMerge:
Daniel Veillard2d38f042000-10-11 10:54:10 +0000590 * @val1: the first NodeSet or NULL
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000591 * @val2: the second NodeSet
592 *
593 * Merges two nodesets, all nodes from @val2 are added to @val1
Daniel Veillard2d38f042000-10-11 10:54:10 +0000594 * if @val1 is NULL, a new set is created and copied from @val2
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000595 *
596 * Returns val1 once extended or NULL in case of error.
597 */
598xmlNodeSetPtr
599xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000600 int i, j, initNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000601
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000602 if (val2 == NULL) return(val1);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000603 if (val1 == NULL) {
604 val1 = xmlXPathNodeSetCreate(NULL);
605 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000606
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000607 initNr = val1->nodeNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000608
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000609 for (i = 0;i < val2->nodeNr;i++) {
610 /*
611 * check against doublons
612 */
613 for (j = 0; j < initNr; j++)
614 if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
615
616 /*
617 * grow the nodeTab if needed
618 */
619 if (val1->nodeMax == 0) {
620 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
621 sizeof(xmlNodePtr));
622 if (val1->nodeTab == NULL) {
623 xmlGenericError(xmlGenericErrorContext,
624 "xmlXPathNodeSetMerge: out of memory\n");
625 return(NULL);
626 }
627 memset(val1->nodeTab, 0 ,
628 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
629 val1->nodeMax = XML_NODESET_DEFAULT;
630 } else if (val1->nodeNr == val1->nodeMax) {
631 xmlNodePtr *temp;
632
633 val1->nodeMax *= 2;
634 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
635 sizeof(xmlNodePtr));
636 if (temp == NULL) {
637 xmlGenericError(xmlGenericErrorContext,
638 "xmlXPathNodeSetMerge: out of memory\n");
639 return(NULL);
640 }
641 val1->nodeTab = temp;
642 }
643 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
644 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000645
646 return(val1);
647}
648
649/**
650 * xmlXPathNodeSetDel:
651 * @cur: the initial node set
652 * @val: an xmlNodePtr
653 *
654 * Removes an xmlNodePtr from an existing NodeSet
655 */
656void
657xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
658 int i;
659
660 if (cur == NULL) return;
661 if (val == NULL) return;
662
663 /*
664 * check against doublons
665 */
666 for (i = 0;i < cur->nodeNr;i++)
667 if (cur->nodeTab[i] == val) break;
668
669 if (i >= cur->nodeNr) {
670#ifdef DEBUG
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000671 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000672 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
673 val->name);
674#endif
675 return;
676 }
677 cur->nodeNr--;
678 for (;i < cur->nodeNr;i++)
679 cur->nodeTab[i] = cur->nodeTab[i + 1];
680 cur->nodeTab[cur->nodeNr] = NULL;
681}
682
683/**
684 * xmlXPathNodeSetRemove:
685 * @cur: the initial node set
686 * @val: the index to remove
687 *
688 * Removes an entry from an existing NodeSet list.
689 */
690void
691xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
692 if (cur == NULL) return;
693 if (val >= cur->nodeNr) return;
694 cur->nodeNr--;
695 for (;val < cur->nodeNr;val++)
696 cur->nodeTab[val] = cur->nodeTab[val + 1];
697 cur->nodeTab[cur->nodeNr] = NULL;
698}
699
700/**
701 * xmlXPathFreeNodeSet:
702 * @obj: the xmlNodeSetPtr to free
703 *
704 * Free the NodeSet compound (not the actual nodes !).
705 */
706void
707xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
708 if (obj == NULL) return;
709 if (obj->nodeTab != NULL) {
710#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000711 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000712#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000713 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000714 }
715#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000716 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000717#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000718 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000719}
720
Daniel Veillardb96e6431999-08-29 21:02:19 +0000721#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000722/**
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000723 * xmlGenericErrorContextNodeSet:
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000724 * @output: a FILE * for the output
725 * @obj: the xmlNodeSetPtr to free
726 *
727 * Quick display of a NodeSet
728 */
729void
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000730xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000731 int i;
732
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000733 if (output == NULL) output = xmlGenericErrorContext;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000734 if (obj == NULL) {
735 fprintf(output, "NodeSet == NULL !\n");
736 return;
737 }
738 if (obj->nodeNr == 0) {
739 fprintf(output, "NodeSet is empty\n");
740 return;
741 }
742 if (obj->nodeTab == NULL) {
743 fprintf(output, " nodeTab == NULL !\n");
744 return;
745 }
746 for (i = 0; i < obj->nodeNr; i++) {
747 if (obj->nodeTab[i] == NULL) {
748 fprintf(output, " NULL !\n");
749 return;
750 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000751 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
752 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000753 fprintf(output, " /");
754 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000755 fprintf(output, " noname!");
756 else fprintf(output, " %s", obj->nodeTab[i]->name);
757 }
758 fprintf(output, "\n");
759}
760#endif
761
Daniel Veillard7e99c632000-10-06 12:59:53 +0000762/**
763 * xmlXPathNewNodeSet:
764 * @val: the NodePtr value
765 *
766 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
767 * it with the single Node @val
768 *
769 * Returns the newly created object.
770 */
771xmlXPathObjectPtr
772xmlXPathNewNodeSet(xmlNodePtr val) {
773 xmlXPathObjectPtr ret;
774
775 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
776 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000777 xmlGenericError(xmlGenericErrorContext,
778 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000779 return(NULL);
780 }
781 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
782 ret->type = XPATH_NODESET;
783 ret->nodesetval = xmlXPathNodeSetCreate(val);
784 return(ret);
785}
786
787/**
788 * xmlXPathNewNodeSetList:
789 * @val: an existing NodeSet
790 *
791 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
792 * it with the Nodeset @val
793 *
794 * Returns the newly created object.
795 */
796xmlXPathObjectPtr
797xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
798 xmlXPathObjectPtr ret;
799 int i;
800
801 if (val == NULL)
802 ret = NULL;
803 else if (val->nodeTab == NULL)
804 ret = xmlXPathNewNodeSet(NULL);
805 else
806 {
807 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
808 for (i = 1; i < val->nodeNr; ++i)
809 xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
810 }
811
812 return(ret);
813}
814
815/**
816 * xmlXPathWrapNodeSet:
817 * @val: the NodePtr value
818 *
819 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
820 *
821 * Returns the newly created object.
822 */
823xmlXPathObjectPtr
824xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
825 xmlXPathObjectPtr ret;
826
827 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
828 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000829 xmlGenericError(xmlGenericErrorContext,
830 "xmlXPathWrapNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000831 return(NULL);
832 }
833 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
834 ret->type = XPATH_NODESET;
835 ret->nodesetval = val;
836 return(ret);
837}
838
839/**
840 * xmlXPathFreeNodeSetList:
841 * @obj: an existing NodeSetList object
842 *
843 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
844 * the list contrary to xmlXPathFreeObject().
845 */
846void
847xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
848 if (obj == NULL) return;
849#ifdef DEBUG
850 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
851#endif
852 xmlFree(obj);
853}
854
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000855/************************************************************************
856 * *
Daniel Veillard2d38f042000-10-11 10:54:10 +0000857 * Routines to handle extra functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000858 * *
859 ************************************************************************/
860
861/**
Daniel Veillard2d38f042000-10-11 10:54:10 +0000862 * xmlXPathRegisterFunc:
863 * @ctxt: the XPath context
864 * @name: the function name
865 * @f: the function implementation or NULL
866 *
867 * Register a new function. If @f is NULL it unregisters the function
868 *
869 * Returns 0 in case of success, -1 in case of error
870 */
871int
872xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
873 xmlXPathFunction f) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +0000874 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
875}
876
877/**
878 * xmlXPathRegisterFuncNS:
879 * @ctxt: the XPath context
880 * @name: the function name
881 * @ns_uri: the function namespace URI
882 * @f: the function implementation or NULL
883 *
884 * Register a new function. If @f is NULL it unregisters the function
885 *
886 * Returns 0 in case of success, -1 in case of error
887 */
888int
889xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
890 const xmlChar *ns_uri, xmlXPathFunction f) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000891 if (ctxt == NULL)
892 return(-1);
893 if (name == NULL)
894 return(-1);
895
Daniel Veillard52afe802000-10-22 16:56:02 +0000896 if (ctxt->funcHash == NULL)
897 ctxt->funcHash = xmlHashCreate(0);
898 if (ctxt->funcHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +0000899 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +0000900 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
Daniel Veillard2d38f042000-10-11 10:54:10 +0000901}
902
903/**
904 * xmlXPathFunctionLookup:
905 * @ctxt: the XPath context
906 * @name: the function name
907 *
908 * Search in the Function array of the context for the given
909 * function.
910 *
911 * Returns the xmlXPathFunction or NULL if not found
912 */
913xmlXPathFunction
914xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +0000915 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
916}
917
918/**
919 * xmlXPathFunctionLookupNS:
920 * @ctxt: the XPath context
921 * @name: the function name
922 * @ns_uri: the function namespace URI
923 *
924 * Search in the Function array of the context for the given
925 * function.
926 *
927 * Returns the xmlXPathFunction or NULL if not found
928 */
929xmlXPathFunction
930xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
931 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000932 if (ctxt == NULL)
933 return(NULL);
Daniel Veillard52afe802000-10-22 16:56:02 +0000934 if (ctxt->funcHash == NULL)
935 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000936 if (name == NULL)
937 return(NULL);
938
Daniel Veillarda5db68a2000-10-29 18:06:06 +0000939 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
Daniel Veillard2d38f042000-10-11 10:54:10 +0000940}
941
942/**
943 * xmlXPathRegisteredFuncsCleanup:
944 * @ctxt: the XPath context
945 *
946 * Cleanup the XPath context data associated to registered functions
947 */
948void
949xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000950 if (ctxt == NULL)
951 return;
952
Daniel Veillard52afe802000-10-22 16:56:02 +0000953 xmlHashFree(ctxt->funcHash, NULL);
954 ctxt->funcHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +0000955}
956
957/************************************************************************
958 * *
959 * Routines to handle Variable *
960 * *
961 ************************************************************************/
962
963/**
964 * xmlXPathRegisterVariable:
965 * @ctxt: the XPath context
966 * @name: the variable name
967 * @value: the variable value or NULL
968 *
969 * Register a new variable value. If @value is NULL it unregisters
970 * the variable
971 *
972 * Returns 0 in case of success, -1 in case of error
973 */
974int
975xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
976 xmlXPathObjectPtr value) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +0000977 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
978}
979
980/**
981 * xmlXPathRegisterVariableNS:
982 * @ctxt: the XPath context
983 * @name: the variable name
984 * @ns_uri: the variable namespace URI
985 * @value: the variable value or NULL
986 *
987 * Register a new variable value. If @value is NULL it unregisters
988 * the variable
989 *
990 * Returns 0 in case of success, -1 in case of error
991 */
992int
993xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
994 const xmlChar *ns_uri,
995 xmlXPathObjectPtr value) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000996 if (ctxt == NULL)
997 return(-1);
998 if (name == NULL)
999 return(-1);
1000
Daniel Veillard126f2792000-10-24 17:10:12 +00001001 if (ctxt->varHash == NULL)
1002 ctxt->varHash = xmlHashCreate(0);
1003 if (ctxt->varHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +00001004 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001005 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1006 (void *) value,
1007 (xmlHashDeallocator)xmlXPathFreeObject));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001008}
1009
1010/**
1011 * xmlXPathVariableLookup:
1012 * @ctxt: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001013 * @name: the variable name
1014 *
1015 * Search in the Variable array of the context for the given
1016 * variable value.
1017 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001018 * Returns the value or NULL if not found
1019 */
1020xmlXPathObjectPtr
Daniel Veillard2d38f042000-10-11 10:54:10 +00001021xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001022 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1023}
1024
1025/**
1026 * xmlXPathVariableLookupNS:
1027 * @ctxt: the XPath context
1028 * @name: the variable name
1029 * @ns_uri: the variable namespace URI
1030 *
1031 * Search in the Variable array of the context for the given
1032 * variable value.
1033 *
1034 * Returns the value or NULL if not found
1035 */
1036xmlXPathObjectPtr
1037xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1038 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001039 if (ctxt == NULL)
1040 return(NULL);
Daniel Veillard126f2792000-10-24 17:10:12 +00001041 if (ctxt->varHash == NULL)
1042 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001043 if (name == NULL)
1044 return(NULL);
1045
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001046 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001047}
1048
Daniel Veillard2d38f042000-10-11 10:54:10 +00001049/**
1050 * xmlXPathRegisteredVariablesCleanup:
1051 * @ctxt: the XPath context
1052 *
1053 * Cleanup the XPath context data associated to registered variables
1054 */
1055void
1056xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001057 if (ctxt == NULL)
1058 return;
1059
Daniel Veillard126f2792000-10-24 17:10:12 +00001060 xmlHashFree(ctxt->varHash, NULL);
1061 ctxt->varHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001062}
1063
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001064/************************************************************************
1065 * *
1066 * Routines to handle Values *
1067 * *
1068 ************************************************************************/
1069
1070/* Allocations are terrible, one need to optimize all this !!! */
1071
1072/**
1073 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001074 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001075 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001076 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001077 *
1078 * Returns the newly created object.
1079 */
1080xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001081xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001082 xmlXPathObjectPtr ret;
1083
Daniel Veillard6454aec1999-09-02 22:04:43 +00001084 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001085 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001086 xmlGenericError(xmlGenericErrorContext,
1087 "xmlXPathNewFloat: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001088 return(NULL);
1089 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001090 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001091 ret->type = XPATH_NUMBER;
1092 ret->floatval = val;
1093 return(ret);
1094}
1095
1096/**
1097 * xmlXPathNewBoolean:
1098 * @val: the boolean value
1099 *
1100 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1101 *
1102 * Returns the newly created object.
1103 */
1104xmlXPathObjectPtr
1105xmlXPathNewBoolean(int val) {
1106 xmlXPathObjectPtr ret;
1107
Daniel Veillard6454aec1999-09-02 22:04:43 +00001108 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001109 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001110 xmlGenericError(xmlGenericErrorContext,
1111 "xmlXPathNewBoolean: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001112 return(NULL);
1113 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001114 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001115 ret->type = XPATH_BOOLEAN;
1116 ret->boolval = (val != 0);
1117 return(ret);
1118}
1119
1120/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001121 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001122 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001123 *
1124 * Create a new xmlXPathObjectPtr of type string and of value @val
1125 *
1126 * Returns the newly created object.
1127 */
1128xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001129xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001130 xmlXPathObjectPtr ret;
1131
Daniel Veillard6454aec1999-09-02 22:04:43 +00001132 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001133 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001134 xmlGenericError(xmlGenericErrorContext,
1135 "xmlXPathNewString: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001136 return(NULL);
1137 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001138 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001139 ret->type = XPATH_STRING;
1140 ret->stringval = xmlStrdup(val);
1141 return(ret);
1142}
1143
1144/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001145 * xmlXPathNewCString:
1146 * @val: the char * value
1147 *
1148 * Create a new xmlXPathObjectPtr of type string and of value @val
1149 *
1150 * Returns the newly created object.
1151 */
1152xmlXPathObjectPtr
1153xmlXPathNewCString(const char *val) {
1154 xmlXPathObjectPtr ret;
1155
Daniel Veillard6454aec1999-09-02 22:04:43 +00001156 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001157 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001158 xmlGenericError(xmlGenericErrorContext,
1159 "xmlXPathNewCString: out of memory\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001160 return(NULL);
1161 }
1162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1163 ret->type = XPATH_STRING;
1164 ret->stringval = xmlStrdup(BAD_CAST val);
1165 return(ret);
1166}
1167
1168/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001169 * xmlXPathObjectCopy:
1170 * @val: the original object
1171 *
1172 * allocate a new copy of a given object
1173 *
1174 * Returns the newly created object.
1175 */
1176xmlXPathObjectPtr
1177xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1178 xmlXPathObjectPtr ret;
1179
1180 if (val == NULL)
1181 return(NULL);
1182
1183 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1184 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001185 xmlGenericError(xmlGenericErrorContext,
1186 "xmlXPathObjectCopy: out of memory\n");
Daniel Veillard2d38f042000-10-11 10:54:10 +00001187 return(NULL);
1188 }
1189 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1190 switch (val->type) {
1191 case XPATH_BOOLEAN:
1192 case XPATH_NUMBER:
1193 case XPATH_STRING:
1194 case XPATH_POINT:
1195 case XPATH_RANGE:
1196 break;
1197 case XPATH_NODESET:
1198 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1199 break;
1200 case XPATH_LOCATIONSET:
1201#ifdef LIBXML_XPTR_ENABLED
1202 {
1203 xmlLocationSetPtr loc = val->user;
1204 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1205 break;
1206 }
1207#endif
1208 case XPATH_UNDEFINED:
1209 case XPATH_USERS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001210 xmlGenericError(xmlGenericErrorContext,
1211 "xmlXPathObjectCopy: unsupported type %d\n",
Daniel Veillard2d38f042000-10-11 10:54:10 +00001212 val->type);
1213 }
1214 return(ret);
1215}
1216
1217/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001218 * xmlXPathFreeObject:
1219 * @obj: the object to free
1220 *
1221 * Free up an xmlXPathObjectPtr object.
1222 */
1223void
1224xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1225 if (obj == NULL) return;
Daniel Veillardac260302000-10-04 13:33:43 +00001226 if (obj->type == XPATH_NODESET) {
1227 if (obj->nodesetval != NULL)
1228 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001229#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard7e99c632000-10-06 12:59:53 +00001230 } else if (obj->type == XPATH_LOCATIONSET) {
1231 if (obj->user != NULL)
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00001232 xmlXPtrFreeLocationSet(obj->user);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001233#endif
Daniel Veillardac260302000-10-04 13:33:43 +00001234 } else if (obj->type == XPATH_STRING) {
1235 if (obj->stringval != NULL)
1236 xmlFree(obj->stringval);
1237 }
1238
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001239#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001240 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001241#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001242 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001243}
1244
1245/************************************************************************
1246 * *
1247 * Routines to handle XPath contexts *
1248 * *
1249 ************************************************************************/
1250
1251/**
1252 * xmlXPathNewContext:
1253 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001254 *
1255 * Create a new xmlXPathContext
1256 *
1257 * Returns the xmlXPathContext just allocated.
1258 */
1259xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001260xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001261 xmlXPathContextPtr ret;
1262
Daniel Veillard6454aec1999-09-02 22:04:43 +00001263 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001264 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001265 xmlGenericError(xmlGenericErrorContext,
1266 "xmlXPathNewContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001267 return(NULL);
1268 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001269 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001270 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001271 ret->node = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001272
Daniel Veillard126f2792000-10-24 17:10:12 +00001273 ret->varHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001274
1275 ret->nb_types = 0;
1276 ret->max_types = 0;
1277 ret->types = NULL;
1278
Daniel Veillard52afe802000-10-22 16:56:02 +00001279 ret->funcHash = xmlHashCreate(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001280
1281 ret->nb_axis = 0;
1282 ret->max_axis = 0;
1283 ret->axis = NULL;
1284
Daniel Veillardb96e6431999-08-29 21:02:19 +00001285 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001286 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001287 ret->nsNr = 0;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001288
1289 ret->contextSize = -1;
1290 ret->proximityPosition = -1;
Daniel Veillard52afe802000-10-22 16:56:02 +00001291
1292 xmlXPathRegisterAllFunctions(ret);
1293
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001294 return(ret);
1295}
1296
1297/**
1298 * xmlXPathFreeContext:
1299 * @ctxt: the context to free
1300 *
1301 * Free up an xmlXPathContext
1302 */
1303void
1304xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001305 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001306 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001307
Daniel Veillard2d38f042000-10-11 10:54:10 +00001308 xmlXPathRegisteredFuncsCleanup(ctxt);
1309 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001310#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001311 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001312#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001313 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001314}
1315
1316/************************************************************************
1317 * *
1318 * Routines to handle XPath parser contexts *
1319 * *
1320 ************************************************************************/
1321
Daniel Veillard740abf52000-10-02 23:04:54 +00001322#define CHECK_CTXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001323 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001324 xmlGenericError(xmlGenericErrorContext, \
1325 "%s:%d Internal error: ctxt == NULL\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001326 __FILE__, __LINE__); \
1327 } \
1328
1329
Daniel Veillard740abf52000-10-02 23:04:54 +00001330#define CHECK_CONTEXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001331 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001332 xmlGenericError(xmlGenericErrorContext, \
1333 "%s:%d Internal error: no context\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001334 __FILE__, __LINE__); \
1335 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001336 else if (ctxt->doc == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001337 xmlGenericError(xmlGenericErrorContext, \
1338 "%s:%d Internal error: no document\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001339 __FILE__, __LINE__); \
1340 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001341 else if (ctxt->doc->children == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001342 xmlGenericError(xmlGenericErrorContext, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001343 "%s:%d Internal error: document without root\n", \
1344 __FILE__, __LINE__); \
1345 } \
1346
1347
1348/**
1349 * xmlXPathNewParserContext:
1350 * @str: the XPath expression
1351 * @ctxt: the XPath context
1352 *
1353 * Create a new xmlXPathParserContext
1354 *
1355 * Returns the xmlXPathParserContext just allocated.
1356 */
1357xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001358xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001359 xmlXPathParserContextPtr ret;
1360
Daniel Veillard6454aec1999-09-02 22:04:43 +00001361 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001362 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001363 xmlGenericError(xmlGenericErrorContext,
1364 "xmlXPathNewParserContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001365 return(NULL);
1366 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001367 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001368 ret->cur = ret->base = str;
1369 ret->context = ctxt;
1370
1371 /* Allocate the value stack */
1372 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001373 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001374 ret->valueNr = 0;
1375 ret->valueMax = 10;
1376 ret->value = NULL;
1377 return(ret);
1378}
1379
1380/**
1381 * xmlXPathFreeParserContext:
1382 * @ctxt: the context to free
1383 *
1384 * Free up an xmlXPathParserContext
1385 */
1386void
1387xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1388 if (ctxt->valueTab != NULL) {
1389#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001390 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001391#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001392 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001393 }
1394#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001395 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001396#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001397 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001398}
1399
1400/************************************************************************
1401 * *
1402 * The implicit core function library *
1403 * *
1404 ************************************************************************/
1405
1406/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001407 * Auto-pop and cast to a number
1408 */
1409void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1410
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001411
1412#define POP_FLOAT \
1413 arg = valuePop(ctxt); \
1414 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001415 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001416 } \
1417 if (arg->type != XPATH_NUMBER) { \
1418 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001419 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001420 arg = valuePop(ctxt); \
1421 }
1422
1423/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001424 * xmlXPathEqualNodeSetString
1425 * @arg: the nodeset object argument
1426 * @str: the string to compare to.
1427 *
1428 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1429 * If one object to be compared is a node-set and the other is a string,
1430 * then the comparison will be true if and only if there is a node in
1431 * the node-set such that the result of performing the comparison on the
1432 * string-value of the node and the other string is true.
1433 *
1434 * Returns 0 or 1 depending on the results of the test.
1435 */
1436int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001437xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001438 int i;
1439 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001440 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001441
1442 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
1443 return(0);
1444 ns = arg->nodesetval;
1445 for (i = 0;i < ns->nodeNr;i++) {
1446 str2 = xmlNodeGetContent(ns->nodeTab[i]);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001447 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001448 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001449 return(1);
1450 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001451 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001452 }
1453 return(0);
1454}
1455
1456/**
1457 * xmlXPathEqualNodeSetFloat
1458 * @arg: the nodeset object argument
1459 * @f: the float to compare to
1460 *
1461 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1462 * If one object to be compared is a node-set and the other is a number,
1463 * then the comparison will be true if and only if there is a node in
1464 * the node-set such that the result of performing the comparison on the
1465 * number to be compared and on the result of converting the string-value
1466 * of that node to a number using the number function is true.
1467 *
1468 * Returns 0 or 1 depending on the results of the test.
1469 */
1470int
1471xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001472 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001473
1474 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1475 return(0);
1476
1477 if (isnan(f))
1478 sprintf(buf, "NaN");
1479 else if (isinf(f) > 0)
1480 sprintf(buf, "+Infinity");
1481 else if (isinf(f) < 0)
1482 sprintf(buf, "-Infinity");
1483 else
1484 sprintf(buf, "%0g", f);
1485
Daniel Veillardb96e6431999-08-29 21:02:19 +00001486 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001487}
1488
1489
1490/**
1491 * xmlXPathEqualNodeSets
1492 * @arg1: first nodeset object argument
1493 * @arg2: second nodeset object argument
1494 *
1495 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1496 * If both objects to be compared are node-sets, then the comparison
1497 * will be true if and only if there is a node in the first node-set and
1498 * a node in the second node-set such that the result of performing the
1499 * comparison on the string-values of the two nodes is true.
1500 *
1501 * (needless to say, this is a costly operation)
1502 *
1503 * Returns 0 or 1 depending on the results of the test.
1504 */
1505int
1506xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1507 int i;
1508 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001509 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001510
1511 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1512 return(0);
1513 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1514 return(0);
1515
1516 ns = arg1->nodesetval;
1517 for (i = 0;i < ns->nodeNr;i++) {
1518 str = xmlNodeGetContent(ns->nodeTab[i]);
1519 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001520 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001521 return(1);
1522 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001523 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001524 }
1525 return(0);
1526}
1527
1528/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001529 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001530 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001531 *
1532 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1533 *
1534 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001535 */
1536int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001537xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1538 xmlXPathObjectPtr arg1, arg2;
1539 int ret = 0;
1540
1541 arg1 = valuePop(ctxt);
1542 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001543 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001544
1545 arg2 = valuePop(ctxt);
1546 if (arg2 == NULL) {
1547 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001548 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001549 }
1550
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001551 if (arg1 == arg2) {
1552#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001553 xmlGenericError(xmlGenericErrorContext,
1554 "Equal: by pointer\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001555#endif
1556 return(1);
1557 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001558
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001559 switch (arg1->type) {
1560 case XPATH_UNDEFINED:
1561#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001562 xmlGenericError(xmlGenericErrorContext,
1563 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001564#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001565 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001566 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001567 switch (arg2->type) {
1568 case XPATH_UNDEFINED:
1569#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001570 xmlGenericError(xmlGenericErrorContext,
1571 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001572#endif
1573 break;
1574 case XPATH_NODESET:
1575 ret = xmlXPathEqualNodeSets(arg1, arg2);
1576 break;
1577 case XPATH_BOOLEAN:
1578 if ((arg1->nodesetval == NULL) ||
1579 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1580 else
1581 ret = 1;
1582 ret = (ret == arg2->boolval);
1583 break;
1584 case XPATH_NUMBER:
1585 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1586 break;
1587 case XPATH_STRING:
1588 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1589 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001590 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001591 case XPATH_POINT:
1592 case XPATH_RANGE:
1593 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001594 TODO
1595 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001596 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001597 break;
1598 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001599 switch (arg2->type) {
1600 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001601#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001602 xmlGenericError(xmlGenericErrorContext,
1603 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001604#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001605 break;
1606 case XPATH_NODESET:
1607 if ((arg2->nodesetval == NULL) ||
1608 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1609 else
1610 ret = 1;
1611 break;
1612 case XPATH_BOOLEAN:
1613#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001614 xmlGenericError(xmlGenericErrorContext,
1615 "Equal: %d boolean %d \n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001616 arg1->boolval, arg2->boolval);
1617#endif
1618 ret = (arg1->boolval == arg2->boolval);
1619 break;
1620 case XPATH_NUMBER:
1621 if (arg2->floatval) ret = 1;
1622 else ret = 0;
1623 ret = (arg1->boolval == ret);
1624 break;
1625 case XPATH_STRING:
1626 if ((arg2->stringval == NULL) ||
1627 (arg2->stringval[0] == 0)) ret = 0;
1628 else
1629 ret = 1;
1630 ret = (arg1->boolval == ret);
1631 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001632 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001633 case XPATH_POINT:
1634 case XPATH_RANGE:
1635 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001636 TODO
1637 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001638 }
1639 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001640 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001641 switch (arg2->type) {
1642 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001643#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001644 xmlGenericError(xmlGenericErrorContext,
1645 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001646#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001647 break;
1648 case XPATH_NODESET:
1649 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1650 break;
1651 case XPATH_BOOLEAN:
1652 if (arg1->floatval) ret = 1;
1653 else ret = 0;
1654 ret = (arg2->boolval == ret);
1655 break;
1656 case XPATH_STRING:
1657 valuePush(ctxt, arg2);
1658 xmlXPathNumberFunction(ctxt, 1);
1659 arg2 = valuePop(ctxt);
1660 /* no break on purpose */
1661 case XPATH_NUMBER:
1662 ret = (arg1->floatval == arg2->floatval);
1663 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001664 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001665 case XPATH_POINT:
1666 case XPATH_RANGE:
1667 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001668 TODO
1669 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001670 }
1671 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001672 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001673 switch (arg2->type) {
1674 case XPATH_UNDEFINED:
1675#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001676 xmlGenericError(xmlGenericErrorContext,
1677 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001678#endif
1679 break;
1680 case XPATH_NODESET:
1681 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1682 break;
1683 case XPATH_BOOLEAN:
1684 if ((arg1->stringval == NULL) ||
1685 (arg1->stringval[0] == 0)) ret = 0;
1686 else
1687 ret = 1;
1688 ret = (arg2->boolval == ret);
1689 break;
1690 case XPATH_STRING:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001691 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001692 break;
1693 case XPATH_NUMBER:
1694 valuePush(ctxt, arg1);
1695 xmlXPathNumberFunction(ctxt, 1);
1696 arg1 = valuePop(ctxt);
1697 ret = (arg1->floatval == arg2->floatval);
1698 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001699 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001700 case XPATH_POINT:
1701 case XPATH_RANGE:
1702 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001703 TODO
1704 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001705 }
1706 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001707 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001708 case XPATH_POINT:
1709 case XPATH_RANGE:
1710 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001711 TODO
1712 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001713 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001714 xmlXPathFreeObject(arg1);
1715 xmlXPathFreeObject(arg2);
1716 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001717}
1718
1719/**
1720 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001721 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001722 * @inf: less than (1) or greater than (2)
1723 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001724 *
1725 * Implement the compare operation on XPath objects:
1726 * @arg1 < @arg2 (1, 1, ...
1727 * @arg1 <= @arg2 (1, 0, ...
1728 * @arg1 > @arg2 (0, 1, ...
1729 * @arg1 >= @arg2 (0, 0, ...
1730 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001731 * When neither object to be compared is a node-set and the operator is
1732 * <=, <, >=, >, then the objects are compared by converted both objects
1733 * to numbers and comparing the numbers according to IEEE 754. The <
1734 * comparison will be true if and only if the first number is less than the
1735 * second number. The <= comparison will be true if and only if the first
1736 * number is less than or equal to the second number. The > comparison
1737 * will be true if and only if the first number is greater than the second
1738 * number. The >= comparison will be true if and only if the first number
1739 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001740 */
1741int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001742xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1743 int ret = 0;
1744 xmlXPathObjectPtr arg1, arg2;
1745
1746 arg2 = valuePop(ctxt);
1747 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1748 if (arg2 != NULL)
1749 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001750 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001751 }
1752
1753 arg1 = valuePop(ctxt);
1754 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1755 if (arg1 != NULL)
1756 xmlXPathFreeObject(arg1);
1757 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001758 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001759 }
1760
1761 if (arg1->type != XPATH_NUMBER) {
1762 valuePush(ctxt, arg1);
1763 xmlXPathNumberFunction(ctxt, 1);
1764 arg1 = valuePop(ctxt);
1765 }
1766 if (arg1->type != XPATH_NUMBER) {
1767 xmlXPathFreeObject(arg1);
1768 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001769 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001770 }
1771 if (arg2->type != XPATH_NUMBER) {
1772 valuePush(ctxt, arg2);
1773 xmlXPathNumberFunction(ctxt, 1);
1774 arg2 = valuePop(ctxt);
1775 }
1776 if (arg2->type != XPATH_NUMBER) {
1777 xmlXPathFreeObject(arg1);
1778 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001779 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001780 }
1781 /*
1782 * Add tests for infinity and nan
1783 * => feedback on 3.4 for Inf and NaN
1784 */
1785 if (inf && strict)
1786 ret = (arg1->floatval < arg2->floatval);
1787 else if (inf && !strict)
1788 ret = (arg1->floatval <= arg2->floatval);
1789 else if (!inf && strict)
1790 ret = (arg1->floatval > arg2->floatval);
1791 else if (!inf && !strict)
1792 ret = (arg1->floatval >= arg2->floatval);
1793 xmlXPathFreeObject(arg1);
1794 xmlXPathFreeObject(arg2);
1795 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001796}
1797
1798/**
1799 * xmlXPathValueFlipSign:
1800 * @ctxt: the XPath Parser context
1801 *
1802 * Implement the unary - operation on an XPath object
1803 * The numeric operators convert their operands to numbers as if
1804 * by calling the number function.
1805 */
1806void
1807xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1808 xmlXPathObjectPtr arg;
1809
1810 POP_FLOAT
1811 arg->floatval = -arg->floatval;
1812 valuePush(ctxt, arg);
1813}
1814
1815/**
1816 * xmlXPathAddValues:
1817 * @ctxt: the XPath Parser context
1818 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001819 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001820 * The numeric operators convert their operands to numbers as if
1821 * by calling the number function.
1822 */
1823void
1824xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1825 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001826 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001827
1828 POP_FLOAT
1829 val = arg->floatval;
1830 xmlXPathFreeObject(arg);
1831
1832 POP_FLOAT
1833 arg->floatval += val;
1834 valuePush(ctxt, arg);
1835}
1836
1837/**
1838 * xmlXPathSubValues:
1839 * @ctxt: the XPath Parser context
1840 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001841 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001842 * The numeric operators convert their operands to numbers as if
1843 * by calling the number function.
1844 */
1845void
1846xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1847 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001848 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001849
1850 POP_FLOAT
1851 val = arg->floatval;
1852 xmlXPathFreeObject(arg);
1853
1854 POP_FLOAT
1855 arg->floatval -= val;
1856 valuePush(ctxt, arg);
1857}
1858
1859/**
1860 * xmlXPathMultValues:
1861 * @ctxt: the XPath Parser context
1862 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001863 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001864 * The numeric operators convert their operands to numbers as if
1865 * by calling the number function.
1866 */
1867void
1868xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1869 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001870 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001871
1872 POP_FLOAT
1873 val = arg->floatval;
1874 xmlXPathFreeObject(arg);
1875
1876 POP_FLOAT
1877 arg->floatval *= val;
1878 valuePush(ctxt, arg);
1879}
1880
1881/**
1882 * xmlXPathDivValues:
1883 * @ctxt: the XPath Parser context
1884 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001885 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001886 * The numeric operators convert their operands to numbers as if
1887 * by calling the number function.
1888 */
1889void
1890xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1891 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001892 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001893
1894 POP_FLOAT
1895 val = arg->floatval;
1896 xmlXPathFreeObject(arg);
1897
1898 POP_FLOAT
1899 arg->floatval /= val;
1900 valuePush(ctxt, arg);
1901}
1902
1903/**
1904 * xmlXPathModValues:
1905 * @ctxt: the XPath Parser context
1906 *
1907 * Implement the div operation on XPath objects: @arg1 / @arg2
1908 * The numeric operators convert their operands to numbers as if
1909 * by calling the number function.
1910 */
1911void
1912xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1913 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001914 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001915
1916 POP_FLOAT
1917 val = arg->floatval;
1918 xmlXPathFreeObject(arg);
1919
1920 POP_FLOAT
1921 arg->floatval /= val;
1922 valuePush(ctxt, arg);
1923}
1924
1925/************************************************************************
1926 * *
1927 * The traversal functions *
1928 * *
1929 ************************************************************************/
1930
Daniel Veillard740abf52000-10-02 23:04:54 +00001931typedef enum {
1932 AXIS_ANCESTOR = 1,
1933 AXIS_ANCESTOR_OR_SELF,
1934 AXIS_ATTRIBUTE,
1935 AXIS_CHILD,
1936 AXIS_DESCENDANT,
1937 AXIS_DESCENDANT_OR_SELF,
1938 AXIS_FOLLOWING,
1939 AXIS_FOLLOWING_SIBLING,
1940 AXIS_NAMESPACE,
1941 AXIS_PARENT,
1942 AXIS_PRECEDING,
1943 AXIS_PRECEDING_SIBLING,
1944 AXIS_SELF
1945} xmlXPathAxisVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001946
1947/*
1948 * A traversal function enumerates nodes along an axis.
1949 * Initially it must be called with NULL, and it indicates
1950 * termination on the axis by returning NULL.
1951 */
1952typedef xmlNodePtr (*xmlXPathTraversalFunction)
1953 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1954
1955/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001956 * xmlXPathNextSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001957 * @ctxt: the XPath Parser context
1958 * @cur: the current node in the traversal
1959 *
1960 * Traversal function for the "self" direction
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001961 * The self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001962 *
1963 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001964 */
1965xmlNodePtr
1966xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1967 if (cur == NULL)
1968 return(ctxt->context->node);
1969 return(NULL);
1970}
1971
1972/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001973 * xmlXPathNextChild:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001974 * @ctxt: the XPath Parser context
1975 * @cur: the current node in the traversal
1976 *
1977 * Traversal function for the "child" direction
1978 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001979 *
1980 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001981 */
1982xmlNodePtr
1983xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001984 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001985 if (ctxt->context->node == NULL) return(NULL);
1986 switch (ctxt->context->node->type) {
1987 case XML_ELEMENT_NODE:
1988 case XML_TEXT_NODE:
1989 case XML_CDATA_SECTION_NODE:
1990 case XML_ENTITY_REF_NODE:
1991 case XML_ENTITY_NODE:
1992 case XML_PI_NODE:
1993 case XML_COMMENT_NODE:
1994 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001995 case XML_DTD_NODE:
1996 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001997 case XML_DOCUMENT_NODE:
1998 case XML_DOCUMENT_TYPE_NODE:
1999 case XML_DOCUMENT_FRAG_NODE:
2000 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002001#ifdef LIBXML_SGML_ENABLED
2002 case XML_SGML_DOCUMENT_NODE:
2003#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002004 return(((xmlDocPtr) ctxt->context->node)->children);
2005 case XML_ELEMENT_DECL:
2006 case XML_ATTRIBUTE_DECL:
2007 case XML_ENTITY_DECL:
2008 case XML_ATTRIBUTE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002009 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002010 case XML_XINCLUDE_START:
2011 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002012 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002013 }
2014 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002015 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002016 if ((cur->type == XML_DOCUMENT_NODE) ||
2017 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002018 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002019 return(cur->next);
2020}
2021
2022/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002023 * xmlXPathNextDescendant:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002024 * @ctxt: the XPath Parser context
2025 * @cur: the current node in the traversal
2026 *
2027 * Traversal function for the "descendant" direction
2028 * the descendant axis contains the descendants of the context node in document
2029 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002030 *
2031 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002032 */
2033xmlNodePtr
2034xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002035 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002036 if (ctxt->context->node == NULL)
2037 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002038 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2039 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002040 return(NULL);
2041
Daniel Veillardb05deb71999-08-10 19:04:08 +00002042 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00002043 return(ctxt->context->doc->children);
2044 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002045 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002046
Daniel Veillardbe803962000-06-28 23:40:59 +00002047 if (cur->children != NULL)
2048 {
2049 if (cur->children->type != XML_ENTITY_DECL)
2050 return(cur->children);
2051 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002052 if (cur->next != NULL) return(cur->next);
2053
2054 do {
2055 cur = cur->parent;
2056 if (cur == NULL) return(NULL);
2057 if (cur == ctxt->context->node) return(NULL);
2058 if (cur->next != NULL) {
2059 cur = cur->next;
2060 return(cur);
2061 }
2062 } while (cur != NULL);
2063 return(cur);
2064}
2065
2066/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002067 * xmlXPathNextDescendantOrSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002068 * @ctxt: the XPath Parser context
2069 * @cur: the current node in the traversal
2070 *
2071 * Traversal function for the "descendant-or-self" direction
2072 * the descendant-or-self axis contains the context node and the descendants
2073 * of the context node in document order; thus the context node is the first
2074 * node on the axis, and the first child of the context node is the second node
2075 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002076 *
2077 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002078 */
2079xmlNodePtr
2080xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002081 if (cur == NULL) {
2082 if (ctxt->context->node == NULL)
2083 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002084 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2085 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002086 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002087 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002088 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002089
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002090 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002091}
2092
2093/**
2094 * xmlXPathNextParent:
2095 * @ctxt: the XPath Parser context
2096 * @cur: the current node in the traversal
2097 *
2098 * Traversal function for the "parent" direction
2099 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002100 *
2101 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002102 */
2103xmlNodePtr
2104xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2105 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002106 * the parent of an attribute or namespace node is the element
2107 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002108 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002109 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002110 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002111 if (ctxt->context->node == NULL) return(NULL);
2112 switch (ctxt->context->node->type) {
2113 case XML_ELEMENT_NODE:
2114 case XML_TEXT_NODE:
2115 case XML_CDATA_SECTION_NODE:
2116 case XML_ENTITY_REF_NODE:
2117 case XML_ENTITY_NODE:
2118 case XML_PI_NODE:
2119 case XML_COMMENT_NODE:
2120 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002121 case XML_DTD_NODE:
2122 case XML_ELEMENT_DECL:
2123 case XML_ATTRIBUTE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002124 case XML_XINCLUDE_START:
2125 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002126 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002127 if (ctxt->context->node->parent == NULL)
2128 return((xmlNodePtr) ctxt->context->doc);
2129 return(ctxt->context->node->parent);
2130 case XML_ATTRIBUTE_NODE: {
2131 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2132
Daniel Veillardcf461992000-03-14 18:30:20 +00002133 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002134 }
2135 case XML_DOCUMENT_NODE:
2136 case XML_DOCUMENT_TYPE_NODE:
2137 case XML_DOCUMENT_FRAG_NODE:
2138 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002139#ifdef LIBXML_SGML_ENABLED
2140 case XML_SGML_DOCUMENT_NODE:
2141#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002142 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002143 case XML_NAMESPACE_DECL:
2144 /*
2145 * TODO !!! may require extending struct _xmlNs with
2146 * parent field
2147 * C.f. Infoset case...
2148 */
2149 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002150 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002151 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002152 return(NULL);
2153}
2154
2155/**
2156 * xmlXPathNextAncestor:
2157 * @ctxt: the XPath Parser context
2158 * @cur: the current node in the traversal
2159 *
2160 * Traversal function for the "ancestor" direction
2161 * the ancestor axis contains the ancestors of the context node; the ancestors
2162 * of the context node consist of the parent of context node and the parent's
2163 * parent and so on; the nodes are ordered in reverse document order; thus the
2164 * parent is the first node on the axis, and the parent's parent is the second
2165 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002166 *
2167 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002168 */
2169xmlNodePtr
2170xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2171 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002172 * the parent of an attribute or namespace node is the element
2173 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002174 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002175 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002176 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002177 if (ctxt->context->node == NULL) return(NULL);
2178 switch (ctxt->context->node->type) {
2179 case XML_ELEMENT_NODE:
2180 case XML_TEXT_NODE:
2181 case XML_CDATA_SECTION_NODE:
2182 case XML_ENTITY_REF_NODE:
2183 case XML_ENTITY_NODE:
2184 case XML_PI_NODE:
2185 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002186 case XML_DTD_NODE:
2187 case XML_ELEMENT_DECL:
2188 case XML_ATTRIBUTE_DECL:
2189 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002190 case XML_NOTATION_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002191 case XML_XINCLUDE_START:
2192 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002193 if (ctxt->context->node->parent == NULL)
2194 return((xmlNodePtr) ctxt->context->doc);
2195 return(ctxt->context->node->parent);
2196 case XML_ATTRIBUTE_NODE: {
2197 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2198
Daniel Veillardcf461992000-03-14 18:30:20 +00002199 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002200 }
2201 case XML_DOCUMENT_NODE:
2202 case XML_DOCUMENT_TYPE_NODE:
2203 case XML_DOCUMENT_FRAG_NODE:
2204 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002205#ifdef LIBXML_SGML_ENABLED
2206 case XML_SGML_DOCUMENT_NODE:
2207#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002208 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002209 case XML_NAMESPACE_DECL:
2210 /*
2211 * TODO !!! may require extending struct _xmlNs with
2212 * parent field
2213 * C.f. Infoset case...
2214 */
2215 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002216 }
2217 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002218 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002219 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002220 return((xmlNodePtr) ctxt->context->doc);
2221 if (cur == (xmlNodePtr) ctxt->context->doc)
2222 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002223 switch (cur->type) {
2224 case XML_ELEMENT_NODE:
2225 case XML_TEXT_NODE:
2226 case XML_CDATA_SECTION_NODE:
2227 case XML_ENTITY_REF_NODE:
2228 case XML_ENTITY_NODE:
2229 case XML_PI_NODE:
2230 case XML_COMMENT_NODE:
2231 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002232 case XML_DTD_NODE:
2233 case XML_ELEMENT_DECL:
2234 case XML_ATTRIBUTE_DECL:
2235 case XML_ENTITY_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002236 case XML_XINCLUDE_START:
2237 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002238 return(cur->parent);
2239 case XML_ATTRIBUTE_NODE: {
2240 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2241
Daniel Veillardcf461992000-03-14 18:30:20 +00002242 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002243 }
2244 case XML_DOCUMENT_NODE:
2245 case XML_DOCUMENT_TYPE_NODE:
2246 case XML_DOCUMENT_FRAG_NODE:
2247 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002248#ifdef LIBXML_SGML_ENABLED
2249 case XML_SGML_DOCUMENT_NODE:
2250#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002251 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002252 case XML_NAMESPACE_DECL:
2253 /*
2254 * TODO !!! may require extending struct _xmlNs with
2255 * parent field
2256 * C.f. Infoset case...
2257 */
2258 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002259 }
2260 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002261}
2262
2263/**
2264 * xmlXPathNextAncestorOrSelf:
2265 * @ctxt: the XPath Parser context
2266 * @cur: the current node in the traversal
2267 *
2268 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00002269 * he ancestor-or-self axis contains the context node and ancestors of
2270 * the context node in reverse document order; thus the context node is
2271 * the first node on the axis, and the context node's parent the second;
2272 * parent here is defined the same as with the parent axis.
2273 *
2274 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002275 */
2276xmlNodePtr
2277xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002278 if (cur == NULL)
2279 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002280 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002281}
2282
2283/**
2284 * xmlXPathNextFollowingSibling:
2285 * @ctxt: the XPath Parser context
2286 * @cur: the current node in the traversal
2287 *
2288 * Traversal function for the "following-sibling" direction
2289 * The following-sibling axis contains the following siblings of the context
2290 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002291 *
2292 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002293 */
2294xmlNodePtr
2295xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002296 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2297 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2298 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002299 if (cur == (xmlNodePtr) ctxt->context->doc)
2300 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002301 if (cur == NULL)
2302 return(ctxt->context->node->next);
2303 return(cur->next);
2304}
2305
2306/**
2307 * xmlXPathNextPrecedingSibling:
2308 * @ctxt: the XPath Parser context
2309 * @cur: the current node in the traversal
2310 *
2311 * Traversal function for the "preceding-sibling" direction
2312 * The preceding-sibling axis contains the preceding siblings of the context
2313 * node in reverse document order; the first preceding sibling is first on the
2314 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002315 *
2316 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002317 */
2318xmlNodePtr
2319xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002320 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2321 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2322 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002323 if (cur == (xmlNodePtr) ctxt->context->doc)
2324 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002325 if (cur == NULL)
2326 return(ctxt->context->node->prev);
2327 return(cur->prev);
2328}
2329
2330/**
2331 * xmlXPathNextFollowing:
2332 * @ctxt: the XPath Parser context
2333 * @cur: the current node in the traversal
2334 *
2335 * Traversal function for the "following" direction
2336 * The following axis contains all nodes in the same document as the context
2337 * node that are after the context node in document order, excluding any
2338 * descendants and excluding attribute nodes and namespace nodes; the nodes
2339 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00002340 *
2341 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002342 */
2343xmlNodePtr
2344xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002345 if (cur != NULL && cur->children != NULL)
2346 return cur->children ;
Daniel Veillardac260302000-10-04 13:33:43 +00002347 if (cur == NULL) cur = ctxt->context->node;
2348 if (cur == NULL) return(NULL) ; /* ERROR */
2349 if (cur->next != NULL) return(cur->next) ;
Daniel Veillard740abf52000-10-02 23:04:54 +00002350 do {
2351 cur = cur->parent;
2352 if (cur == NULL) return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002353 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002354 if (cur->next != NULL) return(cur->next);
Daniel Veillard740abf52000-10-02 23:04:54 +00002355 } while (cur != NULL);
2356 return(cur);
2357}
2358
2359/*
Daniel Veillardac260302000-10-04 13:33:43 +00002360 * xmlXPathIsAncestor:
2361 * @ancestor: the ancestor node
2362 * @node: the current node
2363 *
2364 * Check that @ancestor is a @node's ancestor
2365 *
Daniel Veillard740abf52000-10-02 23:04:54 +00002366 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2367 */
2368static int
Daniel Veillardac260302000-10-04 13:33:43 +00002369xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002370 if ((ancestor == NULL) || (node == NULL)) return(0);
2371 /* nodes need to be in the same document */
2372 if (ancestor->doc != node->doc) return(0);
2373 /* avoid searching if ancestor or node is the root node */
2374 if (ancestor == (xmlNodePtr) node->doc) return(1);
2375 if (node == (xmlNodePtr) ancestor->doc) return(0);
2376 while (node->parent != NULL) {
2377 if (node->parent == ancestor)
2378 return(1);
2379 node = node->parent;
Daniel Veillard740abf52000-10-02 23:04:54 +00002380 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002381 return(0);
Daniel Veillard740abf52000-10-02 23:04:54 +00002382}
2383
2384/**
2385 * xmlXPathNextPreceding:
2386 * @ctxt: the XPath Parser context
2387 * @cur: the current node in the traversal
2388 *
2389 * Traversal function for the "preceding" direction
2390 * the preceding axis contains all nodes in the same document as the context
2391 * node that are before the context node in document order, excluding any
2392 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2393 * ordered in reverse document order
2394 *
2395 * Returns the next element following that axis
2396 */
2397xmlNodePtr
2398xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2399 if (cur == NULL)
2400 cur = ctxt->context->node ;
2401 do {
2402 if (cur->prev != NULL) {
2403 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2404 ;
2405 return(cur) ;
2406 }
2407
2408 cur = cur->parent;
2409 if (cur == NULL) return(NULL);
2410 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002411 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillard740abf52000-10-02 23:04:54 +00002412 return(cur);
2413}
2414
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002415/**
2416 * xmlXPathNextNamespace:
2417 * @ctxt: the XPath Parser context
2418 * @cur: the current attribute in the traversal
2419 *
2420 * Traversal function for the "namespace" direction
2421 * the namespace axis contains the namespace nodes of the context node;
2422 * the order of nodes on this axis is implementation-defined; the axis will
2423 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00002424 *
2425 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002426 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002427xmlNodePtr
2428xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2429 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002430 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2431 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002432 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002433 ctxt->context->namespaces =
2434 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2435 if (ctxt->context->namespaces == NULL) return(NULL);
2436 ctxt->context->nsNr = 0;
2437 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002438 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002439}
2440
2441/**
2442 * xmlXPathNextAttribute:
2443 * @ctxt: the XPath Parser context
2444 * @cur: the current attribute in the traversal
2445 *
2446 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00002447 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00002448 *
2449 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002450 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002451xmlNodePtr
2452xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2453 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002454 if (cur == NULL) {
2455 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2456 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002457 return((xmlNodePtr)ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002458 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002459 return((xmlNodePtr)cur->next);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002460}
2461
2462/************************************************************************
2463 * *
2464 * NodeTest Functions *
2465 * *
2466 ************************************************************************/
2467
Daniel Veillard740abf52000-10-02 23:04:54 +00002468typedef enum {
2469 NODE_TEST_NONE = 0,
2470 NODE_TEST_TYPE = 1,
2471 NODE_TEST_PI = 2,
2472 NODE_TEST_ALL = 3,
2473 NODE_TEST_NS = 4,
2474 NODE_TEST_NAME = 5
2475} xmlXPathTestVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002476
Daniel Veillard740abf52000-10-02 23:04:54 +00002477typedef enum {
Daniel Veillard55b91f22000-10-05 16:30:11 +00002478 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
2479 NODE_TYPE_TEXT = XML_TEXT_NODE,
2480 NODE_TYPE_PI = XML_PI_NODE,
2481 NODE_TYPE_NODE = XML_ELEMENT_NODE
Daniel Veillard740abf52000-10-02 23:04:54 +00002482} xmlXPathTypeVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002483
2484#define IS_FUNCTION 200
2485
2486/**
2487 * xmlXPathNodeCollectAndTest:
2488 * @ctxt: the XPath Parser context
Daniel Veillard740abf52000-10-02 23:04:54 +00002489 * @axis: the XPath axis
2490 * @test: the XPath test
2491 * @type: the XPath type
2492 * @prefix: the namesapce prefix if any
2493 * @name: the name used in the search if any
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002494 *
2495 * This is the function implementing a step: based on the current list
2496 * of nodes, it builds up a new list, looking at all nodes under that
2497 * axis and selecting them.
2498 *
2499 * Returns the new NodeSet resulting from the search.
2500 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002501void
2502xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2503 xmlXPathTestVal test, xmlXPathTypeVal type,
2504 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002505#ifdef DEBUG_STEP
2506 int n = 0, t = 0;
2507#endif
2508 int i;
2509 xmlNodeSetPtr ret;
2510 xmlXPathTraversalFunction next = NULL;
2511 xmlNodePtr cur = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00002512 xmlXPathObjectPtr obj;
2513 xmlNodeSetPtr nodelist;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002514
Daniel Veillard740abf52000-10-02 23:04:54 +00002515 CHECK_TYPE(XPATH_NODESET);
2516 obj = valuePop(ctxt);
2517
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002518#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002519 xmlGenericError(xmlGenericErrorContext,
2520 "new step : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002521#endif
2522 switch (axis) {
2523 case AXIS_ANCESTOR:
2524#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002525 xmlGenericError(xmlGenericErrorContext,
2526 "axis 'ancestors' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002527#endif
2528 next = xmlXPathNextAncestor; break;
2529 case AXIS_ANCESTOR_OR_SELF:
2530#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002531 xmlGenericError(xmlGenericErrorContext,
2532 "axis 'ancestors-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002533#endif
2534 next = xmlXPathNextAncestorOrSelf; break;
2535 case AXIS_ATTRIBUTE:
2536#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002537 xmlGenericError(xmlGenericErrorContext,
2538 "axis 'attributes' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002539#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002540 next = xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002541 break;
2542 case AXIS_CHILD:
2543#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002544 xmlGenericError(xmlGenericErrorContext,
2545 "axis 'child' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002546#endif
2547 next = xmlXPathNextChild; break;
2548 case AXIS_DESCENDANT:
2549#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002550 xmlGenericError(xmlGenericErrorContext,
2551 "axis 'descendant' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002552#endif
2553 next = xmlXPathNextDescendant; break;
2554 case AXIS_DESCENDANT_OR_SELF:
2555#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002556 xmlGenericError(xmlGenericErrorContext,
2557 "axis 'descendant-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002558#endif
2559 next = xmlXPathNextDescendantOrSelf; break;
2560 case AXIS_FOLLOWING:
2561#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002562 xmlGenericError(xmlGenericErrorContext,
2563 "axis 'following' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002564#endif
2565 next = xmlXPathNextFollowing; break;
2566 case AXIS_FOLLOWING_SIBLING:
2567#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002568 xmlGenericError(xmlGenericErrorContext,
2569 "axis 'following-siblings' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002570#endif
2571 next = xmlXPathNextFollowingSibling; break;
2572 case AXIS_NAMESPACE:
2573#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002574 xmlGenericError(xmlGenericErrorContext,
2575 "axis 'namespace' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002576#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002577 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002578 break;
2579 case AXIS_PARENT:
2580#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002581 xmlGenericError(xmlGenericErrorContext,
2582 "axis 'parent' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002583#endif
2584 next = xmlXPathNextParent; break;
2585 case AXIS_PRECEDING:
2586#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002587 xmlGenericError(xmlGenericErrorContext,
2588 "axis 'preceding' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002589#endif
2590 next = xmlXPathNextPreceding; break;
2591 case AXIS_PRECEDING_SIBLING:
2592#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002593 xmlGenericError(xmlGenericErrorContext,
2594 "axis 'preceding-sibling' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002595#endif
2596 next = xmlXPathNextPrecedingSibling; break;
2597 case AXIS_SELF:
2598#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002599 xmlGenericError(xmlGenericErrorContext,
2600 "axis 'self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002601#endif
2602 next = xmlXPathNextSelf; break;
2603 }
Daniel Veillard740abf52000-10-02 23:04:54 +00002604 if (next == NULL)
2605 return;
2606
2607 nodelist = obj->nodesetval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002608 ret = xmlXPathNodeSetCreate(NULL);
2609#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002610 xmlGenericError(xmlGenericErrorContext,
2611 " context contains %d nodes\n",
Daniel Veillard740abf52000-10-02 23:04:54 +00002612 nodelist->nodeNr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002613 switch (test) {
2614 case NODE_TEST_NONE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002615 xmlGenericError(xmlGenericErrorContext,
2616 " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002617 break;
2618 case NODE_TEST_TYPE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002619 xmlGenericError(xmlGenericErrorContext,
2620 " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002621 break;
2622 case NODE_TEST_PI:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002623 xmlGenericError(xmlGenericErrorContext,
2624 " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002625 break;
2626 case NODE_TEST_ALL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002627 xmlGenericError(xmlGenericErrorContext,
2628 " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002629 break;
2630 case NODE_TEST_NS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002631 xmlGenericError(xmlGenericErrorContext,
2632 " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002633 prefix);
2634 break;
2635 case NODE_TEST_NAME:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002636 xmlGenericError(xmlGenericErrorContext,
2637 " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002638 if (prefix != NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002639 xmlGenericError(xmlGenericErrorContext,
2640 " with namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002641 prefix);
2642 break;
2643 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002644 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002645#endif
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00002646 /*
2647 * 2.3 Node Tests
2648 * - For the attribute axis, the principal node type is attribute.
2649 * - For the namespace axis, the principal node type is namespace.
2650 * - For other axes, the principal node type is element.
2651 *
2652 * A node test * is true for any node of the
2653 * principal node type. For example, child::* willi
2654 * select all element children of the context node
2655 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002656 for (i = 0;i < nodelist->nodeNr; i++) {
2657 ctxt->context->node = nodelist->nodeTab[i];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002658
2659 cur = NULL;
2660 do {
2661 cur = next(ctxt, cur);
2662 if (cur == NULL) break;
2663#ifdef DEBUG_STEP
2664 t++;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002665 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002666#endif
2667 switch (test) {
2668 case NODE_TEST_NONE:
2669 STRANGE
Daniel Veillard740abf52000-10-02 23:04:54 +00002670 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002671 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002672 if ((cur->type == type) ||
2673 ((type == XML_ELEMENT_NODE) &&
2674 ((cur->type == XML_DOCUMENT_NODE) ||
2675 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002676#ifdef DEBUG_STEP
2677 n++;
2678#endif
2679 xmlXPathNodeSetAdd(ret, cur);
2680 }
2681 break;
2682 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002683 if (cur->type == XML_PI_NODE) {
2684 if ((name != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002685 (!xmlStrEqual(name, cur->name)))
Daniel Veillardb96e6431999-08-29 21:02:19 +00002686 break;
2687#ifdef DEBUG_STEP
2688 n++;
2689#endif
2690 xmlXPathNodeSetAdd(ret, cur);
2691 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002692 break;
2693 case NODE_TEST_ALL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002694 if (axis == AXIS_ATTRIBUTE) {
2695 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002696#ifdef DEBUG_STEP
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002697 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002698#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002699 xmlXPathNodeSetAdd(ret, cur);
2700 }
2701 } else if (axis == AXIS_NAMESPACE) {
2702 if (cur->type == XML_NAMESPACE_DECL) {
2703#ifdef DEBUG_STEP
2704 n++;
2705#endif
2706 xmlXPathNodeSetAdd(ret, cur);
2707 }
2708 } else {
2709 if ((cur->type == XML_ELEMENT_NODE) ||
2710 (cur->type == XML_DOCUMENT_NODE) ||
2711 (cur->type == XML_HTML_DOCUMENT_NODE)) {
2712#ifdef DEBUG_STEP
2713 n++;
2714#endif
2715 xmlXPathNodeSetAdd(ret, cur);
2716 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002717 }
2718 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002719 case NODE_TEST_NS: {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002720 TODO;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002721 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002722 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002723 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002724 switch (cur->type) {
2725 case XML_ELEMENT_NODE:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002726 if (xmlStrEqual(name, cur->name) &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002727 (((prefix == NULL) ||
2728 ((cur->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002729 (xmlStrEqual(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002730#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002731 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002732#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002733 xmlXPathNodeSetAdd(ret, cur);
2734 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002735 break;
2736 case XML_ATTRIBUTE_NODE: {
2737 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002738 if (xmlStrEqual(name, attr->name)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002739#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002740 n++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002741#endif
2742 xmlXPathNodeSetAdd(ret, cur);
2743 }
2744 break;
2745 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002746 case XML_NAMESPACE_DECL: {
2747 TODO;
2748 break;
2749 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002750 default:
2751 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002752 }
2753 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002754 }
2755 } while (cur != NULL);
2756 }
2757#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002758 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002759 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2760#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00002761 xmlXPathFreeObject(obj);
2762 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002763}
2764
2765
2766/************************************************************************
2767 * *
2768 * Implicit tree core function library *
2769 * *
2770 ************************************************************************/
2771
2772/**
2773 * xmlXPathRoot:
2774 * @ctxt: the XPath Parser context
2775 *
2776 * Initialize the context to the root of the document
2777 */
2778void
2779xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002780 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Daniel Veillard740abf52000-10-02 23:04:54 +00002781 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002782}
2783
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002784/************************************************************************
2785 * *
2786 * The explicit core function library *
2787 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2788 * *
2789 ************************************************************************/
2790
2791
2792/**
2793 * xmlXPathLastFunction:
2794 * @ctxt: the XPath Parser context
2795 *
2796 * Implement the last() XPath function
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002797 * number last()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002798 * The last function returns the number of nodes in the context node list.
2799 */
2800void
2801xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2802 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002803 if (ctxt->context->contextSize > 0) {
2804 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
2805#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002806 xmlGenericError(xmlGenericErrorContext,
2807 "last() : %d\n", ctxt->context->contextSize);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002808#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002809 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002810 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002811 }
2812}
2813
2814/**
2815 * xmlXPathPositionFunction:
2816 * @ctxt: the XPath Parser context
2817 *
2818 * Implement the position() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00002819 * number position()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002820 * The position function returns the position of the context node in the
2821 * context node list. The first position is 1, and so the last positionr
2822 * will be equal to last().
2823 */
2824void
2825xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002826 CHECK_ARITY(0);
Daniel Veillardff9c3302000-10-13 16:38:25 +00002827 if (ctxt->context->proximityPosition >= 0) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002828 valuePush(ctxt,
Daniel Veillardff9c3302000-10-13 16:38:25 +00002829 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002830#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002831 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002832 ctxt->context->proximityPosition);
2833#endif
2834 } else {
2835 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002836 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002837}
2838
2839/**
2840 * xmlXPathCountFunction:
2841 * @ctxt: the XPath Parser context
2842 *
2843 * Implement the count() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00002844 * number count(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002845 */
2846void
2847xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2848 xmlXPathObjectPtr cur;
2849
2850 CHECK_ARITY(1);
2851 CHECK_TYPE(XPATH_NODESET);
2852 cur = valuePop(ctxt);
2853
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002854 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002855 xmlXPathFreeObject(cur);
2856}
2857
2858/**
2859 * xmlXPathIdFunction:
2860 * @ctxt: the XPath Parser context
2861 *
2862 * Implement the id() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00002863 * node-set id(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002864 * The id function selects elements by their unique ID
2865 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2866 * then the result is the union of the result of applying id to the
2867 * string value of each of the nodes in the argument node-set. When the
2868 * argument to id is of any other type, the argument is converted to a
2869 * string as if by a call to the string function; the string is split
2870 * into a whitespace-separated list of tokens (whitespace is any sequence
2871 * of characters matching the production S); the result is a node-set
2872 * containing the elements in the same document as the context node that
2873 * have a unique ID equal to any of the tokens in the list.
2874 */
2875void
2876xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002877 const xmlChar *tokens;
2878 const xmlChar *cur;
2879 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002880 xmlAttrPtr attr;
2881 xmlNodePtr elem = NULL;
2882 xmlXPathObjectPtr ret, obj;
2883
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002884 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002885 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002886 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002887 if (obj->type == XPATH_NODESET) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002888 xmlXPathObjectPtr newobj;
2889 int i;
2890
2891 ret = xmlXPathNewNodeSet(NULL);
2892
2893 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
2894 valuePush(ctxt,
2895 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
2896 xmlXPathStringFunction(ctxt, 1);
2897 xmlXPathIdFunction(ctxt, 1);
2898 newobj = valuePop(ctxt);
2899 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
2900 newobj->nodesetval);
2901 xmlXPathFreeObject(newobj);
2902 }
2903
2904 xmlXPathFreeObject(obj);
2905 valuePush(ctxt, ret);
2906 return;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002907 }
2908 if (obj->type != XPATH_STRING) {
2909 valuePush(ctxt, obj);
2910 xmlXPathStringFunction(ctxt, 1);
2911 obj = valuePop(ctxt);
2912 if (obj->type != XPATH_STRING) {
2913 xmlXPathFreeObject(obj);
2914 return;
2915 }
2916 }
2917 tokens = obj->stringval;
2918
2919 ret = xmlXPathNewNodeSet(NULL);
2920 valuePush(ctxt, ret);
2921 if (tokens == NULL) {
2922 xmlXPathFreeObject(obj);
2923 return;
2924 }
2925
2926 cur = tokens;
2927
2928 while (IS_BLANK(*cur)) cur++;
2929 while (*cur != 0) {
2930 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2931 (*cur == '.') || (*cur == '-') ||
2932 (*cur == '_') || (*cur == ':') ||
2933 (IS_COMBINING(*cur)) ||
2934 (IS_EXTENDER(*cur)))
2935 cur++;
2936
2937 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2938
2939 ID = xmlStrndup(tokens, cur - tokens);
2940 attr = xmlGetID(ctxt->context->doc, ID);
2941 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002942 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002943 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2944 }
2945 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002946 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002947
2948 while (IS_BLANK(*cur)) cur++;
2949 tokens = cur;
2950 }
2951 xmlXPathFreeObject(obj);
2952 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002953}
2954
2955/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002956 * xmlXPathLocalNameFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002957 * @ctxt: the XPath Parser context
2958 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002959 * Implement the local-name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00002960 * string local-name(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002961 * The local-name function returns a string containing the local part
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002962 * of the name of the node in the argument node-set that is first in
2963 * document order. If the node-set is empty or the first node has no
2964 * name, an empty string is returned. If the argument is omitted it
2965 * defaults to the context node.
2966 */
2967void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002968xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002969 xmlXPathObjectPtr cur;
2970
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002971 if (nargs == 0) {
2972 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2973 nargs = 1;
2974 }
2975
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002976 CHECK_ARITY(1);
2977 CHECK_TYPE(XPATH_NODESET);
2978 cur = valuePop(ctxt);
2979
2980 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002981 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002982 } else {
2983 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00002984 switch (cur->nodesetval->nodeTab[i]->type) {
2985 case XML_ELEMENT_NODE:
2986 case XML_ATTRIBUTE_NODE:
2987 case XML_PI_NODE:
2988 valuePush(ctxt,
2989 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2990 break;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002991 case XML_NAMESPACE_DECL:
2992 valuePush(ctxt, xmlXPathNewString(
2993 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
2994 break;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00002995 default:
2996 valuePush(ctxt, xmlXPathNewCString(""));
2997 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002998 }
2999 xmlXPathFreeObject(cur);
3000}
3001
3002/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003003 * xmlXPathNamespaceURIFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003004 * @ctxt: the XPath Parser context
3005 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003006 * Implement the namespace-uri() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003007 * string namespace-uri(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003008 * The namespace-uri function returns a string containing the
3009 * namespace URI of the expanded name of the node in the argument
3010 * node-set that is first in document order. If the node-set is empty,
3011 * the first node has no name, or the expanded name has no namespace
3012 * URI, an empty string is returned. If the argument is omitted it
3013 * defaults to the context node.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003014 */
3015void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003016xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003017 xmlXPathObjectPtr cur;
3018
Daniel Veillardb96e6431999-08-29 21:02:19 +00003019 if (nargs == 0) {
3020 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3021 nargs = 1;
3022 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003023 CHECK_ARITY(1);
3024 CHECK_TYPE(XPATH_NODESET);
3025 cur = valuePop(ctxt);
3026
3027 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003028 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003029 } else {
3030 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003031 switch (cur->nodesetval->nodeTab[i]->type) {
3032 case XML_ELEMENT_NODE:
3033 case XML_ATTRIBUTE_NODE:
3034 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3035 valuePush(ctxt, xmlXPathNewCString(""));
3036 else
3037 valuePush(ctxt, xmlXPathNewString(
3038 cur->nodesetval->nodeTab[i]->ns->href));
3039 break;
3040 default:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003041 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003042 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003043 }
3044 xmlXPathFreeObject(cur);
3045}
3046
3047/**
3048 * xmlXPathNameFunction:
3049 * @ctxt: the XPath Parser context
3050 *
3051 * Implement the name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003052 * string name(node-set?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003053 * The name function returns a string containing a QName representing
3054 * the name of the node in the argument node-set that is first in documenti
3055 * order. The QName must represent the name with respect to the namespace
3056 * declarations in effect on the node whose name is being represented.
3057 * Typically, this will be the form in which the name occurred in the XML
3058 * source. This need not be the case if there are namespace declarations
3059 * in effect on the node that associate multiple prefixes with the same
3060 * namespace. However, an implementation may include information about
3061 * the original prefix in its representation of nodes; in this case, an
3062 * implementation can ensure that the returned string is always the same
3063 * as the QName used in the XML source. If the argument it omitted it
3064 * defaults to the context node.
3065 * Libxml keep the original prefix so the "real qualified name" used is
3066 * returned.
3067 */
3068void
3069xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3070 xmlXPathObjectPtr cur;
3071
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003072 if (nargs == 0) {
3073 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3074 nargs = 1;
3075 }
3076
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003077 CHECK_ARITY(1);
3078 CHECK_TYPE(XPATH_NODESET);
3079 cur = valuePop(ctxt);
3080
3081 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003082 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003083 } else {
3084 int i = 0; /* Should be first in document order !!!!! */
3085
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003086 switch (cur->nodesetval->nodeTab[i]->type) {
3087 case XML_ELEMENT_NODE:
3088 case XML_ATTRIBUTE_NODE:
3089 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3090 valuePush(ctxt, xmlXPathNewString(
3091 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003092
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003093 else {
3094 char name[2000];
Daniel Veillard39c7d712000-09-10 16:14:55 +00003095#ifdef HAVE_SNPRINTF
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003096 snprintf(name, sizeof(name), "%s:%s",
3097 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3098 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003099#else
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003100 sprintf(name, "%s:%s",
3101 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3102 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003103#endif
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003104 name[sizeof(name) - 1] = 0;
3105 valuePush(ctxt, xmlXPathNewCString(name));
3106 }
3107 break;
3108 default:
3109 valuePush(ctxt,
3110 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3111 xmlXPathLocalNameFunction(ctxt, 1);
3112 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003113 }
3114 xmlXPathFreeObject(cur);
3115}
3116
3117/**
3118 * xmlXPathStringFunction:
3119 * @ctxt: the XPath Parser context
3120 *
3121 * Implement the string() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003122 * string string(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003123 * he string function converts an object to a string as follows:
3124 * - A node-set is converted to a string by returning the value of
3125 * the node in the node-set that is first in document order.
3126 * If the node-set is empty, an empty string is returned.
3127 * - A number is converted to a string as follows
3128 * + NaN is converted to the string NaN
3129 * + positive zero is converted to the string 0
3130 * + negative zero is converted to the string 0
3131 * + positive infinity is converted to the string Infinity
3132 * + negative infinity is converted to the string -Infinity
3133 * + if the number is an integer, the number is represented in
3134 * decimal form as a Number with no decimal point and no leading
3135 * zeros, preceded by a minus sign (-) if the number is negative
3136 * + otherwise, the number is represented in decimal form as a
3137 * Number including a decimal point with at least one digit
3138 * before the decimal point and at least one digit after the
3139 * decimal point, preceded by a minus sign (-) if the number
3140 * is negative; there must be no leading zeros before the decimal
3141 * point apart possibly from the one required digit immediatelyi
3142 * before the decimal point; beyond the one required digit
3143 * after the decimal point there must be as many, but only as
3144 * many, more digits as are needed to uniquely distinguish the
3145 * number from all other IEEE 754 numeric values.
3146 * - The boolean false value is converted to the string false.
3147 * The boolean true value is converted to the string true.
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003148 *
3149 * If the argument is omitted, it defaults to a node-set with the
3150 * context node as its only member.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003151 */
3152void
3153xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3154 xmlXPathObjectPtr cur;
3155
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003156 if (nargs == 0) {
3157 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3158 nargs = 1;
3159 }
3160
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003161 CHECK_ARITY(1);
3162 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003163 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003164 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003165 case XPATH_UNDEFINED:
3166#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003167 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00003168#endif
3169 valuePush(ctxt, xmlXPathNewCString(""));
3170 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003171 case XPATH_NODESET:
3172 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003173 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003174 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003175 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003176 int i = 0; /* Should be first in document order !!!!! */
3177 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
3178 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003179 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003180 }
3181 xmlXPathFreeObject(cur);
3182 return;
3183 case XPATH_STRING:
3184 valuePush(ctxt, cur);
3185 return;
3186 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003187 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
3188 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003189 xmlXPathFreeObject(cur);
3190 return;
3191 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003192 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003193
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003194 if (isnan(cur->floatval))
3195 sprintf(buf, "NaN");
3196 else if (isinf(cur->floatval) > 0)
3197 sprintf(buf, "+Infinity");
3198 else if (isinf(cur->floatval) < 0)
3199 sprintf(buf, "-Infinity");
3200 else
3201 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003202 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003203 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003204 return;
3205 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003206 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003207 case XPATH_POINT:
3208 case XPATH_RANGE:
3209 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003210 TODO
3211 valuePush(ctxt, xmlXPathNewCString(""));
3212 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003213 }
3214 STRANGE
3215}
3216
3217/**
3218 * xmlXPathStringLengthFunction:
3219 * @ctxt: the XPath Parser context
3220 *
3221 * Implement the string-length() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003222 * number string-length(string?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003223 * The string-length returns the number of characters in the string
3224 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3225 * the context node converted to a string, in other words the value
3226 * of the context node.
3227 */
3228void
3229xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3230 xmlXPathObjectPtr cur;
3231
3232 if (nargs == 0) {
3233 if (ctxt->context->node == NULL) {
3234 valuePush(ctxt, xmlXPathNewFloat(0));
3235 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003236 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003237
3238 content = xmlNodeGetContent(ctxt->context->node);
3239 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003240 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003241 }
3242 return;
3243 }
3244 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003245 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003246 CHECK_TYPE(XPATH_STRING);
3247 cur = valuePop(ctxt);
3248 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3249 xmlXPathFreeObject(cur);
3250}
3251
3252/**
3253 * xmlXPathConcatFunction:
3254 * @ctxt: the XPath Parser context
3255 *
3256 * Implement the concat() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003257 * string concat(string, string, string*)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003258 * The concat function returns the concatenation of its arguments.
3259 */
3260void
3261xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003262 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003263 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003264
3265 if (nargs < 2) {
3266 CHECK_ARITY(2);
3267 }
3268
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003269 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003270 cur = valuePop(ctxt);
3271 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3272 xmlXPathFreeObject(cur);
3273 return;
3274 }
3275 nargs--;
3276
3277 while (nargs > 0) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003278 CAST_TO_STRING;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003279 newobj = valuePop(ctxt);
3280 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3281 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003282 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003283 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003284 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003285 tmp = xmlStrcat(newobj->stringval, cur->stringval);
3286 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003287 cur->stringval = tmp;
3288
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003289 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003290 nargs--;
3291 }
3292 valuePush(ctxt, cur);
3293}
3294
3295/**
3296 * xmlXPathContainsFunction:
3297 * @ctxt: the XPath Parser context
3298 *
3299 * Implement the contains() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003300 * boolean contains(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003301 * The contains function returns true if the first argument string
3302 * contains the second argument string, and otherwise returns false.
3303 */
3304void
3305xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3306 xmlXPathObjectPtr hay, needle;
3307
3308 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003309 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003310 CHECK_TYPE(XPATH_STRING);
3311 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003312 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003313 hay = valuePop(ctxt);
3314 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3315 xmlXPathFreeObject(hay);
3316 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003317 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003318 }
3319 if (xmlStrstr(hay->stringval, needle->stringval))
3320 valuePush(ctxt, xmlXPathNewBoolean(1));
3321 else
3322 valuePush(ctxt, xmlXPathNewBoolean(0));
3323 xmlXPathFreeObject(hay);
3324 xmlXPathFreeObject(needle);
3325}
3326
3327/**
3328 * xmlXPathStartsWithFunction:
3329 * @ctxt: the XPath Parser context
3330 *
3331 * Implement the starts-with() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003332 * boolean starts-with(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003333 * The starts-with function returns true if the first argument string
3334 * starts with the second argument string, and otherwise returns false.
3335 */
3336void
3337xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3338 xmlXPathObjectPtr hay, needle;
3339 int n;
3340
3341 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003342 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003343 CHECK_TYPE(XPATH_STRING);
3344 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003345 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 hay = valuePop(ctxt);
3347 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3348 xmlXPathFreeObject(hay);
3349 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003350 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003351 }
3352 n = xmlStrlen(needle->stringval);
3353 if (xmlStrncmp(hay->stringval, needle->stringval, n))
3354 valuePush(ctxt, xmlXPathNewBoolean(0));
3355 else
3356 valuePush(ctxt, xmlXPathNewBoolean(1));
3357 xmlXPathFreeObject(hay);
3358 xmlXPathFreeObject(needle);
3359}
3360
3361/**
3362 * xmlXPathSubstringFunction:
3363 * @ctxt: the XPath Parser context
3364 *
3365 * Implement the substring() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003366 * string substring(string, number, number?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003367 * The substring function returns the substring of the first argument
3368 * starting at the position specified in the second argument with
3369 * length specified in the third argument. For example,
3370 * substring("12345",2,3) returns "234". If the third argument is not
3371 * specified, it returns the substring starting at the position specified
3372 * in the second argument and continuing to the end of the string. For
3373 * example, substring("12345",2) returns "2345". More precisely, each
3374 * character in the string (see [3.6 Strings]) is considered to have a
3375 * numeric position: the position of the first character is 1, the position
3376 * of the second character is 2 and so on. The returned substring contains
3377 * those characters for which the position of the character is greater than
3378 * or equal to the second argument and, if the third argument is specified,
3379 * less than the sum of the second and third arguments; the comparisons
3380 * and addition used for the above follow the standard IEEE 754 rules. Thus:
3381 * - substring("12345", 1.5, 2.6) returns "234"
3382 * - substring("12345", 0, 3) returns "12"
3383 * - substring("12345", 0 div 0, 3) returns ""
3384 * - substring("12345", 1, 0 div 0) returns ""
3385 * - substring("12345", -42, 1 div 0) returns "12345"
3386 * - substring("12345", -1 div 0, 1 div 0) returns ""
3387 */
3388void
3389xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3390 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003391 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003392 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003393 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003394
3395 /*
3396 * Conformance needs to be checked !!!!!
3397 */
3398 if (nargs < 2) {
3399 CHECK_ARITY(2);
3400 }
3401 if (nargs > 3) {
3402 CHECK_ARITY(3);
3403 }
3404 if (nargs == 3) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003405 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003406 CHECK_TYPE(XPATH_NUMBER);
3407 len = valuePop(ctxt);
3408 le = len->floatval;
3409 xmlXPathFreeObject(len);
3410 } else {
3411 le = 2000000000;
3412 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003413 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003414 CHECK_TYPE(XPATH_NUMBER);
3415 start = valuePop(ctxt);
3416 in = start->floatval;
3417 xmlXPathFreeObject(start);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003418 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003419 CHECK_TYPE(XPATH_STRING);
3420 str = valuePop(ctxt);
3421 le += in;
3422
3423 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003424 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003425 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003426
3427 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003428 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003429 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003430
3431 /* back to a zero based len */
3432 i--;
3433 l--;
3434
3435 /* check against the string len */
3436 if (l > 1024) {
3437 l = xmlStrlen(str->stringval);
3438 }
3439 if (i < 0) {
3440 i = 0;
3441 }
3442
3443 /* number of chars to copy */
3444 l -= i;
3445
3446 ret = xmlStrsub(str->stringval, i, l);
3447 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00003448 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003449 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003450 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003451 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003452 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003453 xmlXPathFreeObject(str);
3454}
3455
3456/**
3457 * xmlXPathSubstringBeforeFunction:
3458 * @ctxt: the XPath Parser context
3459 *
3460 * Implement the substring-before() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003461 * string substring-before(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003462 * The substring-before function returns the substring of the first
3463 * argument string that precedes the first occurrence of the second
3464 * argument string in the first argument string, or the empty string
3465 * if the first argument string does not contain the second argument
3466 * string. For example, substring-before("1999/04/01","/") returns 1999.
3467 */
3468void
3469xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003470 xmlXPathObjectPtr str;
3471 xmlXPathObjectPtr find;
3472 xmlBufferPtr target;
3473 const xmlChar *point;
3474 int offset;
3475
3476 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003477 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003478 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003479 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003480 str = valuePop(ctxt);
3481
3482 target = xmlBufferCreate();
3483 if (target) {
3484 point = xmlStrstr(str->stringval, find->stringval);
3485 if (point) {
3486 offset = (int)(point - str->stringval);
3487 xmlBufferAdd(target, str->stringval, offset);
3488 }
3489 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3490 xmlBufferFree(target);
3491 }
3492
3493 xmlXPathFreeObject(str);
3494 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003495}
3496
3497/**
3498 * xmlXPathSubstringAfterFunction:
3499 * @ctxt: the XPath Parser context
3500 *
3501 * Implement the substring-after() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003502 * string substring-after(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003503 * The substring-after function returns the substring of the first
3504 * argument string that follows the first occurrence of the second
3505 * argument string in the first argument string, or the empty stringi
3506 * if the first argument string does not contain the second argument
3507 * string. For example, substring-after("1999/04/01","/") returns 04/01,
3508 * and substring-after("1999/04/01","19") returns 99/04/01.
3509 */
3510void
3511xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003512 xmlXPathObjectPtr str;
3513 xmlXPathObjectPtr find;
3514 xmlBufferPtr target;
3515 const xmlChar *point;
3516 int offset;
3517
3518 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003519 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003520 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003521 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003522 str = valuePop(ctxt);
3523
3524 target = xmlBufferCreate();
3525 if (target) {
3526 point = xmlStrstr(str->stringval, find->stringval);
3527 if (point) {
3528 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
3529 xmlBufferAdd(target, &str->stringval[offset],
3530 xmlStrlen(str->stringval) - offset);
3531 }
3532 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3533 xmlBufferFree(target);
3534 }
3535
3536 xmlXPathFreeObject(str);
3537 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003538}
3539
3540/**
3541 * xmlXPathNormalizeFunction:
3542 * @ctxt: the XPath Parser context
3543 *
Daniel Veillard767662d2000-10-27 17:04:52 +00003544 * Implement the normalize-space() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003545 * string normalize-space(string?)
Daniel Veillard767662d2000-10-27 17:04:52 +00003546 * The normalize-space function returns the argument string with white
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003547 * space normalized by stripping leading and trailing whitespace
3548 * and replacing sequences of whitespace characters by a single
3549 * space. Whitespace characters are the same allowed by the S production
3550 * in XML. If the argument is omitted, it defaults to the context
3551 * node converted to a string, in other words the value of the context node.
3552 */
3553void
3554xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003555 xmlXPathObjectPtr obj = NULL;
3556 xmlChar *source = NULL;
3557 xmlBufferPtr target;
3558 xmlChar blank;
3559
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003560 if (nargs == 0) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003561 /* Use current context node */
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003562 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3563 xmlXPathStringFunction(ctxt, 1);
3564 nargs = 1;
Daniel Veillard46057e12000-09-24 18:49:59 +00003565 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003566
3567 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003568 CAST_TO_STRING;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003569 CHECK_TYPE(XPATH_STRING);
3570 obj = valuePop(ctxt);
3571 source = obj->stringval;
3572
Daniel Veillard46057e12000-09-24 18:49:59 +00003573 target = xmlBufferCreate();
3574 if (target && source) {
3575
3576 /* Skip leading whitespaces */
3577 while (IS_BLANK(*source))
3578 source++;
3579
3580 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
3581 blank = 0;
3582 while (*source) {
3583 if (IS_BLANK(*source)) {
3584 blank = *source;
3585 } else {
3586 if (blank) {
3587 xmlBufferAdd(target, &blank, 1);
3588 blank = 0;
3589 }
3590 xmlBufferAdd(target, source, 1);
3591 }
3592 source++;
3593 }
3594
3595 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3596 xmlBufferFree(target);
3597 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003598 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003599}
3600
3601/**
3602 * xmlXPathTranslateFunction:
3603 * @ctxt: the XPath Parser context
3604 *
3605 * Implement the translate() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003606 * string translate(string, string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003607 * The translate function returns the first argument string with
3608 * occurrences of characters in the second argument string replaced
3609 * by the character at the corresponding position in the third argument
3610 * string. For example, translate("bar","abc","ABC") returns the string
3611 * BAr. If there is a character in the second argument string with no
3612 * character at a corresponding position in the third argument string
3613 * (because the second argument string is longer than the third argument
3614 * string), then occurrences of that character in the first argument
3615 * string are removed. For example, translate("--aaa--","abc-","ABC")
3616 * returns "AAA". If a character occurs more than once in second
3617 * argument string, then the first occurrence determines the replacement
3618 * character. If the third argument string is longer than the second
3619 * argument string, then excess characters are ignored.
3620 */
3621void
3622xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003623 xmlXPathObjectPtr str;
3624 xmlXPathObjectPtr from;
3625 xmlXPathObjectPtr to;
3626 xmlBufferPtr target;
3627 int i, offset, max;
3628 xmlChar ch;
3629 const xmlChar *point;
3630
3631 CHECK_ARITY(3);
3632
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003633 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003634 to = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003635 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003636 from = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003637 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003638 str = valuePop(ctxt);
3639
3640 target = xmlBufferCreate();
3641 if (target) {
3642 max = xmlStrlen(to->stringval);
3643 for (i = 0; (ch = str->stringval[i]); i++) {
3644 point = xmlStrchr(from->stringval, ch);
3645 if (point) {
3646 /* Warning: This may not work with UTF-8 */
3647 offset = (int)(point - from->stringval);
3648 if (offset < max)
3649 xmlBufferAdd(target, &to->stringval[offset], 1);
3650 } else
3651 xmlBufferAdd(target, &ch, 1);
3652 }
3653 }
3654 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3655 xmlBufferFree(target);
3656 xmlXPathFreeObject(str);
3657 xmlXPathFreeObject(from);
3658 xmlXPathFreeObject(to);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003659}
3660
3661/**
3662 * xmlXPathBooleanFunction:
3663 * @ctxt: the XPath Parser context
3664 *
3665 * Implement the boolean() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003666 * boolean boolean(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003667 * he boolean function converts its argument to a boolean as follows:
3668 * - a number is true if and only if it is neither positive or
3669 * negative zero nor NaN
3670 * - a node-set is true if and only if it is non-empty
3671 * - a string is true if and only if its length is non-zero
3672 */
3673void
3674xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3675 xmlXPathObjectPtr cur;
3676 int res = 0;
3677
3678 CHECK_ARITY(1);
3679 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003680 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003681 switch (cur->type) {
3682 case XPATH_NODESET:
3683 if ((cur->nodesetval == NULL) ||
3684 (cur->nodesetval->nodeNr == 0)) res = 0;
3685 else
3686 res = 1;
3687 break;
3688 case XPATH_STRING:
3689 if ((cur->stringval == NULL) ||
3690 (cur->stringval[0] == 0)) res = 0;
3691 else
3692 res = 1;
3693 break;
3694 case XPATH_BOOLEAN:
3695 valuePush(ctxt, cur);
3696 return;
3697 case XPATH_NUMBER:
3698 if (cur->floatval) res = 1;
3699 break;
3700 default:
3701 STRANGE
3702 }
3703 xmlXPathFreeObject(cur);
3704 valuePush(ctxt, xmlXPathNewBoolean(res));
3705}
3706
3707/**
3708 * xmlXPathNotFunction:
3709 * @ctxt: the XPath Parser context
3710 *
3711 * Implement the not() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003712 * boolean not(boolean)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003713 * The not function returns true if its argument is false,
3714 * and false otherwise.
3715 */
3716void
3717xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3718 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003719 CAST_TO_BOOLEAN;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003720 CHECK_TYPE(XPATH_BOOLEAN);
3721 ctxt->value->boolval = ! ctxt->value->boolval;
3722}
3723
3724/**
3725 * xmlXPathTrueFunction:
3726 * @ctxt: the XPath Parser context
3727 *
3728 * Implement the true() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003729 * boolean true()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003730 */
3731void
3732xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3733 CHECK_ARITY(0);
3734 valuePush(ctxt, xmlXPathNewBoolean(1));
3735}
3736
3737/**
3738 * xmlXPathFalseFunction:
3739 * @ctxt: the XPath Parser context
3740 *
3741 * Implement the false() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003742 * boolean false()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003743 */
3744void
3745xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3746 CHECK_ARITY(0);
3747 valuePush(ctxt, xmlXPathNewBoolean(0));
3748}
3749
3750/**
3751 * xmlXPathLangFunction:
3752 * @ctxt: the XPath Parser context
3753 *
3754 * Implement the lang() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003755 * boolean lang(string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003756 * The lang function returns true or false depending on whether the
3757 * language of the context node as specified by xml:lang attributes
3758 * is the same as or is a sublanguage of the language specified by
3759 * the argument string. The language of the context node is determined
3760 * by the value of the xml:lang attribute on the context node, or, if
3761 * the context node has no xml:lang attribute, by the value of the
3762 * xml:lang attribute on the nearest ancestor of the context node that
3763 * has an xml:lang attribute. If there is no such attribute, then lang
3764 * returns false. If there is such an attribute, then lang returns
3765 * true if the attribute value is equal to the argument ignoring case,
3766 * or if there is some suffix starting with - such that the attribute
3767 * value is equal to the argument ignoring that suffix of the attribute
3768 * value and ignoring case.
3769 */
3770void
3771xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003772 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003773 const xmlChar *theLang;
3774 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003775 int ret = 0;
3776 int i;
3777
3778 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003779 CAST_TO_STRING;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003780 CHECK_TYPE(XPATH_STRING);
3781 val = valuePop(ctxt);
3782 lang = val->stringval;
3783 theLang = xmlNodeGetLang(ctxt->context->node);
3784 if ((theLang != NULL) && (lang != NULL)) {
3785 for (i = 0;lang[i] != 0;i++)
3786 if (toupper(lang[i]) != toupper(theLang[i]))
3787 goto not_equal;
3788 ret = 1;
3789 }
3790not_equal:
3791 xmlXPathFreeObject(val);
3792 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003793}
3794
3795/**
3796 * xmlXPathNumberFunction:
3797 * @ctxt: the XPath Parser context
3798 *
3799 * Implement the number() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003800 * number number(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003801 */
3802void
3803xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3804 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003805 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003806
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003807 if (nargs == 0) {
3808 if (ctxt->context->node == NULL) {
3809 valuePush(ctxt, xmlXPathNewFloat(0.0));
3810 } else {
3811 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
3812
3813 res = xmlXPathStringEvalNumber(content);
3814 valuePush(ctxt, xmlXPathNewFloat(res));
3815 xmlFree(content);
3816 }
3817 return;
3818 }
3819
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003820 CHECK_ARITY(1);
3821 cur = valuePop(ctxt);
3822 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003823 case XPATH_UNDEFINED:
3824#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003825 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00003826#endif
3827 valuePush(ctxt, xmlXPathNewFloat(0.0));
3828 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003829 case XPATH_NODESET:
3830 valuePush(ctxt, cur);
3831 xmlXPathStringFunction(ctxt, 1);
3832 cur = valuePop(ctxt);
3833 case XPATH_STRING:
3834 res = xmlXPathStringEvalNumber(cur->stringval);
3835 valuePush(ctxt, xmlXPathNewFloat(res));
3836 xmlXPathFreeObject(cur);
3837 return;
3838 case XPATH_BOOLEAN:
3839 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
3840 else valuePush(ctxt, xmlXPathNewFloat(0.0));
3841 xmlXPathFreeObject(cur);
3842 return;
3843 case XPATH_NUMBER:
3844 valuePush(ctxt, cur);
3845 return;
Daniel Veillard740abf52000-10-02 23:04:54 +00003846 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003847 case XPATH_POINT:
3848 case XPATH_RANGE:
3849 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003850 TODO
3851 valuePush(ctxt, xmlXPathNewFloat(0.0));
3852 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003853 }
3854 STRANGE
3855}
3856
3857/**
3858 * xmlXPathSumFunction:
3859 * @ctxt: the XPath Parser context
3860 *
3861 * Implement the sum() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003862 * number sum(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003863 * The sum function returns the sum of the values of the nodes in
3864 * the argument node-set.
3865 */
3866void
3867xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003868 xmlXPathObjectPtr cur;
3869 int i;
3870
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003871 CHECK_ARITY(1);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003872 CHECK_TYPE(XPATH_NODESET);
3873 cur = valuePop(ctxt);
3874
3875 if (cur->nodesetval->nodeNr == 0) {
3876 valuePush(ctxt, xmlXPathNewFloat(0.0));
3877 } else {
3878 valuePush(ctxt,
3879 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
Daniel Veillard767662d2000-10-27 17:04:52 +00003880 xmlXPathNumberFunction(ctxt, 1);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003881 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
3882 valuePush(ctxt,
3883 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3884 xmlXPathAddValues(ctxt);
3885 }
3886 }
3887 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003888}
3889
3890/**
3891 * xmlXPathFloorFunction:
3892 * @ctxt: the XPath Parser context
3893 *
3894 * Implement the floor() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003895 * number floor(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003896 * The floor function returns the largest (closest to positive infinity)
3897 * number that is not greater than the argument and that is an integer.
3898 */
3899void
3900xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3901 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003902 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003903 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003904#if 0
3905 ctxt->value->floatval = floor(ctxt->value->floatval);
3906#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003907 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003908 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003909#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003910}
3911
3912/**
3913 * xmlXPathCeilingFunction:
3914 * @ctxt: the XPath Parser context
3915 *
3916 * Implement the ceiling() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003917 * number ceiling(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003918 * The ceiling function returns the smallest (closest to negative infinity)
3919 * number that is not less than the argument and that is an integer.
3920 */
3921void
3922xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003923 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003924
3925 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003926 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003927 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003928
3929#if 0
3930 ctxt->value->floatval = ceil(ctxt->value->floatval);
3931#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003932 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003933 if (f != ctxt->value->floatval)
3934 ctxt->value->floatval = f + 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003935#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003936}
3937
3938/**
3939 * xmlXPathRoundFunction:
3940 * @ctxt: the XPath Parser context
3941 *
3942 * Implement the round() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003943 * number round(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003944 * The round function returns the number that is closest to the
3945 * argument and that is an integer. If there are two such numbers,
3946 * then the one that is even is returned.
3947 */
3948void
3949xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003950 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003951
3952 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003953 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003954 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003955
3956 if ((ctxt->value->floatval == xmlXPathNAN) ||
3957 (ctxt->value->floatval == xmlXPathPINF) ||
3958 (ctxt->value->floatval == xmlXPathNINF) ||
3959 (ctxt->value->floatval == 0.0))
3960 return;
3961
3962#if 0
3963 f = floor(ctxt->value->floatval);
3964#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003965 f = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003966#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003967 if (ctxt->value->floatval < f + 0.5)
3968 ctxt->value->floatval = f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003969 else
3970 ctxt->value->floatval = f + 1;
3971}
3972
3973/************************************************************************
3974 * *
3975 * The Parser *
3976 * *
3977 ************************************************************************/
3978
3979/*
3980 * a couple of forward declarations since we use a recursive call based
3981 * implementation.
3982 */
3983void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3984void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3985void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3986void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3987
3988/**
3989 * xmlXPathParseNCName:
3990 * @ctxt: the XPath Parser context
3991 *
3992 * parse an XML namespace non qualified name.
3993 *
3994 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3995 *
3996 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3997 * CombiningChar | Extender
3998 *
3999 * Returns the namespace name or NULL
4000 */
4001
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004002xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004003xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004004 const xmlChar *q;
4005 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004006
4007 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4008 q = NEXT;
4009
4010 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4011 (CUR == '.') || (CUR == '-') ||
4012 (CUR == '_') ||
4013 (IS_COMBINING(CUR)) ||
4014 (IS_EXTENDER(CUR)))
4015 NEXT;
4016
4017 ret = xmlStrndup(q, CUR_PTR - q);
4018
4019 return(ret);
4020}
4021
4022/**
4023 * xmlXPathParseQName:
4024 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004025 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004026 *
4027 * parse an XML qualified name
4028 *
4029 * [NS 5] QName ::= (Prefix ':')? LocalPart
4030 *
4031 * [NS 6] Prefix ::= NCName
4032 *
4033 * [NS 7] LocalPart ::= NCName
4034 *
4035 * Returns the function returns the local part, and prefix is updated
4036 * to get the Prefix if any.
4037 */
4038
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004039xmlChar *
4040xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
4041 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004042
4043 *prefix = NULL;
4044 ret = xmlXPathParseNCName(ctxt);
4045 if (CUR == ':') {
4046 *prefix = ret;
4047 NEXT;
4048 ret = xmlXPathParseNCName(ctxt);
4049 }
4050 return(ret);
4051}
4052
4053/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00004054 * xmlXPathParseName:
4055 * @ctxt: the XPointer Parser context
4056 *
4057 * parse an XML name
4058 *
4059 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4060 * CombiningChar | Extender
4061 *
4062 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4063 *
4064 * Returns the namespace name or NULL
4065 */
4066
4067xmlChar *
4068xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
4069 const xmlChar *q;
4070 xmlChar *ret = NULL;
4071
4072 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4073 q = NEXT;
4074
4075 /* TODO Make this UTF8 compliant !!! */
4076 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4077 (CUR == '.') || (CUR == '-') ||
4078 (CUR == '_') || (CUR == ':') ||
4079 (IS_COMBINING(CUR)) ||
4080 (IS_EXTENDER(CUR)))
4081 NEXT;
4082
4083 ret = xmlStrndup(q, CUR_PTR - q);
4084
4085 return(ret);
4086}
4087
4088/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004089 * xmlXPathStringEvalNumber:
4090 * @str: A string to scan
4091 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004092 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004093 * | '.' Digits
4094 * [31] Digits ::= [0-9]+
4095 *
4096 * Parse and evaluate a Number in the string
Daniel Veillard767662d2000-10-27 17:04:52 +00004097 * In complement of the Number expression, this function also handles
4098 * negative values : '-' Number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004099 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004100 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004101 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004102double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004103xmlXPathStringEvalNumber(const xmlChar *str) {
4104 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004105 double ret = 0.0;
4106 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004107 int ok = 0;
Daniel Veillard767662d2000-10-27 17:04:52 +00004108 int isneg = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004109
4110 while (*cur == ' ') cur++;
Daniel Veillard767662d2000-10-27 17:04:52 +00004111 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004112 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004113 }
Daniel Veillard767662d2000-10-27 17:04:52 +00004114 if (*cur == '-') {
4115 isneg = 1;
4116 cur++;
4117 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004118 while ((*cur >= '0') && (*cur <= '9')) {
4119 ret = ret * 10 + (*cur - '0');
4120 ok = 1;
4121 cur++;
4122 }
4123 if (*cur == '.') {
4124 cur++;
4125 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004126 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004127 }
4128 while ((*cur >= '0') && (*cur <= '9')) {
4129 mult /= 10;
4130 ret = ret + (*cur - '0') * mult;
4131 cur++;
4132 }
4133 }
4134 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004135 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard767662d2000-10-27 17:04:52 +00004136 if (isneg) ret = -ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004137 return(ret);
4138}
4139
4140/**
4141 * xmlXPathEvalNumber:
4142 * @ctxt: the XPath Parser context
4143 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004144 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004145 * | '.' Digits
4146 * [31] Digits ::= [0-9]+
4147 *
4148 * Parse and evaluate a Number, then push it on the stack
4149 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004150 */
4151void
4152xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004153 double ret = 0.0;
4154 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004155 int ok = 0;
4156
4157 CHECK_ERROR;
4158 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004159 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004160 }
4161 while ((CUR >= '0') && (CUR <= '9')) {
4162 ret = ret * 10 + (CUR - '0');
4163 ok = 1;
4164 NEXT;
4165 }
4166 if (CUR == '.') {
4167 NEXT;
4168 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004169 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004170 }
4171 while ((CUR >= '0') && (CUR <= '9')) {
4172 mult /= 10;
4173 ret = ret + (CUR - '0') * mult;
4174 NEXT;
4175 }
4176 }
4177 valuePush(ctxt, xmlXPathNewFloat(ret));
4178}
4179
4180/**
4181 * xmlXPathEvalLiteral:
4182 * @ctxt: the XPath Parser context
4183 *
4184 * Parse a Literal and push it on the stack.
4185 *
4186 * [29] Literal ::= '"' [^"]* '"'
4187 * | "'" [^']* "'"
4188 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004189 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004190 */
4191void
4192xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004193 const xmlChar *q;
4194 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004195
4196 if (CUR == '"') {
4197 NEXT;
4198 q = CUR_PTR;
4199 while ((IS_CHAR(CUR)) && (CUR != '"'))
4200 NEXT;
4201 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004202 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004203 } else {
4204 ret = xmlStrndup(q, CUR_PTR - q);
4205 NEXT;
4206 }
4207 } else if (CUR == '\'') {
4208 NEXT;
4209 q = CUR_PTR;
4210 while ((IS_CHAR(CUR)) && (CUR != '\''))
4211 NEXT;
4212 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004213 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004214 } else {
4215 ret = xmlStrndup(q, CUR_PTR - q);
4216 NEXT;
4217 }
4218 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004219 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004220 }
4221 if (ret == NULL) return;
4222 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004223 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004224}
4225
4226/**
4227 * xmlXPathEvalVariableReference:
4228 * @ctxt: the XPath Parser context
4229 *
4230 * Parse a VariableReference, evaluate it and push it on the stack.
4231 *
4232 * The variable bindings consist of a mapping from variable names
4233 * to variable values. The value of a variable is an object, which
4234 * of any of the types that are possible for the value of an expression,
4235 * and may also be of additional types not specified here.
4236 *
4237 * Early evaluation is possible since:
4238 * The variable bindings [...] used to evaluate a subexpression are
4239 * always the same as those used to evaluate the containing expression.
4240 *
4241 * [36] VariableReference ::= '$' QName
4242 */
4243void
4244xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004245 xmlChar *name;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004246 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004247 xmlXPathObjectPtr value;
4248
Daniel Veillard55b91f22000-10-05 16:30:11 +00004249 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004250 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004251 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004252 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004253 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004254 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004255 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004256 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004257 if (prefix == NULL) {
4258 value = xmlXPathVariableLookup(ctxt->context, name);
4259 } else {
4260 TODO;
4261 value = NULL;
4262 }
4263 xmlFree(name);
4264 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004265 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004266 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004267 }
4268 valuePush(ctxt, value);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004269 SKIP_BLANKS;
4270}
4271
4272/**
4273 * xmlXPathIsNodeType:
4274 * @ctxt: the XPath Parser context
4275 * @name: a name string
4276 *
4277 * Is the name given a NodeType one.
4278 *
4279 * [38] NodeType ::= 'comment'
4280 * | 'text'
4281 * | 'processing-instruction'
4282 * | 'node'
4283 *
4284 * Returns 1 if true 0 otherwise
4285 */
4286int
4287xmlXPathIsNodeType(const xmlChar *name) {
4288 if (name == NULL)
4289 return(0);
4290
4291 if (xmlStrEqual(name, BAD_CAST "comment"))
4292 return(1);
4293 if (xmlStrEqual(name, BAD_CAST "text"))
4294 return(1);
4295 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4296 return(1);
4297 if (xmlStrEqual(name, BAD_CAST "node"))
4298 return(1);
4299 return(0);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004300}
4301
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004302/**
4303 * xmlXPathEvalFunctionCall:
4304 * @ctxt: the XPath Parser context
4305 *
4306 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4307 * [17] Argument ::= Expr
4308 *
4309 * Parse and evaluate a function call, the evaluation of all arguments are
4310 * pushed on the stack
4311 */
4312void
4313xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004314 xmlChar *name;
4315 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004316 xmlXPathFunction func;
4317 int nbargs = 0;
4318
4319 name = xmlXPathParseQName(ctxt, &prefix);
4320 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004321 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004322 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004323 SKIP_BLANKS;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004324 if (prefix == NULL) {
4325 func = xmlXPathFunctionLookup(ctxt->context, name);
4326 } else {
4327 TODO;
4328 func = NULL;
4329 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004330 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004331 xmlFree(name);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004332 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004333 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004334 }
4335#ifdef DEBUG_EXPR
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004336 if (prefix == NULL)
4337 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
4338 name);
4339 else
4340 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
4341 prefix, name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004342#endif
4343
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004344 xmlFree(name);
4345 if (prefix != NULL) xmlFree(prefix);
4346
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004347 if (CUR != '(') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004348 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004349 }
4350 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004351 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004352
4353 while (CUR != ')') {
4354 xmlXPathEvalExpr(ctxt);
4355 nbargs++;
4356 if (CUR == ')') break;
4357 if (CUR != ',') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004358 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004359 }
4360 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004361 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004362 }
4363 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004364 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004365 func(ctxt, nbargs);
4366}
4367
4368/**
4369 * xmlXPathEvalPrimaryExpr:
4370 * @ctxt: the XPath Parser context
4371 *
4372 * [15] PrimaryExpr ::= VariableReference
4373 * | '(' Expr ')'
4374 * | Literal
4375 * | Number
4376 * | FunctionCall
4377 *
4378 * Parse and evaluate a primary expression, then push the result on the stack
4379 */
4380void
4381xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004382 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004383 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4384 else if (CUR == '(') {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004385 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004386 SKIP_BLANKS;
Daniel Veillard55b91f22000-10-05 16:30:11 +00004387 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004388 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004389 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004390 }
4391 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004392 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004393 } else if (IS_DIGIT(CUR)) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004394 xmlXPathEvalNumber(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004395 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004396 xmlXPathEvalLiteral(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004397 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004398 xmlXPathEvalFunctionCall(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004399 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004400 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004401}
4402
4403/**
4404 * xmlXPathEvalFilterExpr:
4405 * @ctxt: the XPath Parser context
4406 *
4407 * [20] FilterExpr ::= PrimaryExpr
4408 * | FilterExpr Predicate
4409 *
4410 * Parse and evaluate a filter expression, then push the result on the stack
4411 * Square brackets are used to filter expressions in the same way that
4412 * they are used in location paths. It is an error if the expression to
4413 * be filtered does not evaluate to a node-set. The context node list
4414 * used for evaluating the expression in square brackets is the node-set
4415 * to be filtered listed in document order.
4416 */
4417
4418void
4419xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004420 xmlXPathEvalPrimaryExpr(ctxt);
4421 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004422 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004423
4424 if (CUR != '[') return;
4425
4426 CHECK_TYPE(XPATH_NODESET);
4427
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004428 while (CUR == '[') {
4429 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004430 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004431 }
4432
4433
4434}
4435
4436/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00004437 * xmlXPathScanName:
4438 * @ctxt: the XPath Parser context
4439 *
4440 * Trickery: parse an XML name but without consuming the input flow
Daniel Veillard55b91f22000-10-05 16:30:11 +00004441 * Needed to avoid insanity in the parser state.
Daniel Veillardb96e6431999-08-29 21:02:19 +00004442 *
4443 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4444 * CombiningChar | Extender
4445 *
4446 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4447 *
4448 * [6] Names ::= Name (S Name)*
4449 *
4450 * Returns the Name parsed or NULL
4451 */
4452
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004453xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004454xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004455 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00004456 int len = 0;
4457
Daniel Veillard00fdf371999-10-08 09:40:39 +00004458 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004459 if (!IS_LETTER(CUR) && (CUR != '_') &&
4460 (CUR != ':')) {
4461 return(NULL);
4462 }
4463
4464 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4465 (NXT(len) == '.') || (NXT(len) == '-') ||
4466 (NXT(len) == '_') || (NXT(len) == ':') ||
4467 (IS_COMBINING(NXT(len))) ||
4468 (IS_EXTENDER(NXT(len)))) {
4469 buf[len] = NXT(len);
4470 len++;
4471 if (len >= XML_MAX_NAMELEN) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004472 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardb96e6431999-08-29 21:02:19 +00004473 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
4474 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4475 (NXT(len) == '.') || (NXT(len) == '-') ||
4476 (NXT(len) == '_') || (NXT(len) == ':') ||
4477 (IS_COMBINING(NXT(len))) ||
4478 (IS_EXTENDER(NXT(len))))
4479 len++;
4480 break;
4481 }
4482 }
4483 return(xmlStrndup(buf, len));
4484}
4485
4486/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004487 * xmlXPathEvalPathExpr:
4488 * @ctxt: the XPath Parser context
4489 *
4490 * [19] PathExpr ::= LocationPath
4491 * | FilterExpr
4492 * | FilterExpr '/' RelativeLocationPath
4493 * | FilterExpr '//' RelativeLocationPath
4494 *
4495 * Parse and evaluate a path expression, then push the result on the stack
4496 * The / operator and // operators combine an arbitrary expression
4497 * and a relative location path. It is an error if the expression
4498 * does not evaluate to a node-set.
4499 * The / operator does composition in the same way as when / is
4500 * used in a location path. As in location paths, // is short for
4501 * /descendant-or-self::node()/.
4502 */
4503
4504void
4505xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004506 int lc = 1; /* Should we branch to LocationPath ? */
4507 xmlChar *name = NULL; /* we may have to preparse a name to find out */
4508
Daniel Veillard00fdf371999-10-08 09:40:39 +00004509 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004510 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
4511 (CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004512 lc = 0;
4513 } else if (CUR == '/') {
4514 /* relative or absolute location path */
4515 lc = 1;
4516 } else if (CUR == '@') {
4517 /* relative abbreviated attribute location path */
4518 lc = 1;
4519 } else if (CUR == '.') {
4520 /* relative abbreviated attribute location path */
4521 lc = 1;
4522 } else {
4523 /*
4524 * Problem is finding if we have a name here whether it's:
4525 * - a nodetype
4526 * - a function call in which case it's followed by '('
4527 * - an axis in which case it's followed by ':'
4528 * - a element name
4529 * We do an a priori analysis here rather than having to
4530 * maintain parsed token content through the recursive function
4531 * calls. This looks uglier but makes the code quite easier to
4532 * read/write/debug.
4533 */
4534 SKIP_BLANKS;
4535 name = xmlXPathScanName(ctxt);
4536 if (name != NULL) {
4537 int len =xmlStrlen(name);
4538 int blank = 0;
4539
4540 while (NXT(len) != 0) {
4541 if (NXT(len) == '/') {
4542 /* element name */
4543#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004544 xmlGenericError(xmlGenericErrorContext,
4545 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004546#endif
4547 lc = 1;
4548 break;
4549 } else if (IS_BLANK(NXT(len))) {
4550 /* skip to next */
4551 blank = 1;
4552 } else if (NXT(len) == ':') {
4553#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004554 xmlGenericError(xmlGenericErrorContext,
4555 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004556#endif
4557 lc = 1;
4558 break;
4559 } else if ((NXT(len) == '(')) {
4560 /* Note Type or Function */
4561 if (xmlXPathIsNodeType(name)) {
4562#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004563 xmlGenericError(xmlGenericErrorContext,
4564 "PathExpr: Type search\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004565#endif
4566 lc = 1;
4567 } else {
4568#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004569 xmlGenericError(xmlGenericErrorContext,
4570 "PathExpr: function call\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004571#endif
4572 lc = 0;
4573 }
4574 break;
4575 } else if ((NXT(len) == '[')) {
4576 /* element name */
4577#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004578 xmlGenericError(xmlGenericErrorContext,
4579 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004580#endif
4581 lc = 1;
4582 break;
4583 } else {
4584 XP_ERROR(XPATH_EXPR_ERROR);
4585 }
4586 len++;
4587 }
4588 if (NXT(len) == 0) {
4589#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004590 xmlGenericError(xmlGenericErrorContext,
4591 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004592#endif
4593 /* element name */
4594 lc = 1;
4595 }
4596 xmlFree(name);
4597 } else {
4598 /* make sure all cases are covered explicitely */
4599 XP_ERROR(XPATH_EXPR_ERROR);
4600 }
4601 }
4602
4603 if (lc) {
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00004604 if (CUR == '/')
4605 xmlXPathRoot(ctxt);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004606 xmlXPathEvalLocationPath(ctxt);
4607 } else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004608 xmlXPathEvalFilterExpr(ctxt);
4609 CHECK_ERROR;
4610 if ((CUR == '/') && (NXT(1) == '/')) {
4611 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004612 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00004613 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00004614 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004615 ctxt->context->node = NULL;
4616 xmlXPathEvalRelativeLocationPath(ctxt);
4617 } else if (CUR == '/') {
4618 xmlXPathEvalRelativeLocationPath(ctxt);
4619 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004620 }
4621 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004622}
4623
4624/**
4625 * xmlXPathEvalUnionExpr:
4626 * @ctxt: the XPath Parser context
4627 *
4628 * [18] UnionExpr ::= PathExpr
4629 * | UnionExpr '|' PathExpr
4630 *
4631 * Parse and evaluate an union expression, then push the result on the stack
4632 */
4633
4634void
4635xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
4636 xmlXPathEvalPathExpr(ctxt);
4637 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004638 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004639 if (CUR == '|') {
Daniel Veillard740abf52000-10-02 23:04:54 +00004640 xmlXPathObjectPtr obj1,obj2;
4641
4642 CHECK_TYPE(XPATH_NODESET);
4643 obj1 = valuePop(ctxt);
4644 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004645
Daniel Veillard00fdf371999-10-08 09:40:39 +00004646 NEXT;
4647 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004648 xmlXPathEvalPathExpr(ctxt);
4649
Daniel Veillard740abf52000-10-02 23:04:54 +00004650 CHECK_TYPE(XPATH_NODESET);
4651 obj2 = valuePop(ctxt);
4652 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
4653 obj2->nodesetval);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00004654 valuePush(ctxt, obj1);
Daniel Veillard740abf52000-10-02 23:04:54 +00004655 xmlXPathFreeObject(obj2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004656 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004657 }
4658}
4659
4660/**
4661 * xmlXPathEvalUnaryExpr:
4662 * @ctxt: the XPath Parser context
4663 *
4664 * [27] UnaryExpr ::= UnionExpr
4665 * | '-' UnaryExpr
4666 *
4667 * Parse and evaluate an unary expression, then push the result on the stack
4668 */
4669
4670void
4671xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
4672 int minus = 0;
4673
Daniel Veillard00fdf371999-10-08 09:40:39 +00004674 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004675 if (CUR == '-') {
4676 minus = 1;
4677 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004678 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004679 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004680 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004681 CHECK_ERROR;
4682 if (minus) {
4683 xmlXPathValueFlipSign(ctxt);
4684 }
4685}
4686
4687/**
4688 * xmlXPathEvalMultiplicativeExpr:
4689 * @ctxt: the XPath Parser context
4690 *
4691 * [26] MultiplicativeExpr ::= UnaryExpr
4692 * | MultiplicativeExpr MultiplyOperator UnaryExpr
4693 * | MultiplicativeExpr 'div' UnaryExpr
4694 * | MultiplicativeExpr 'mod' UnaryExpr
4695 * [34] MultiplyOperator ::= '*'
4696 *
4697 * Parse and evaluate an Additive expression, then push the result on the stack
4698 */
4699
4700void
4701xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
4702 xmlXPathEvalUnaryExpr(ctxt);
4703 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004704 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004705 while ((CUR == '*') ||
4706 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
4707 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
4708 int op = -1;
4709
4710 if (CUR == '*') {
4711 op = 0;
4712 NEXT;
4713 } else if (CUR == 'd') {
4714 op = 1;
4715 SKIP(3);
4716 } else if (CUR == 'm') {
4717 op = 2;
4718 SKIP(3);
4719 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004720 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004721 xmlXPathEvalUnaryExpr(ctxt);
4722 CHECK_ERROR;
4723 switch (op) {
4724 case 0:
4725 xmlXPathMultValues(ctxt);
4726 break;
4727 case 1:
4728 xmlXPathDivValues(ctxt);
4729 break;
4730 case 2:
4731 xmlXPathModValues(ctxt);
4732 break;
4733 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004734 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004735 }
4736}
4737
4738/**
4739 * xmlXPathEvalAdditiveExpr:
4740 * @ctxt: the XPath Parser context
4741 *
4742 * [25] AdditiveExpr ::= MultiplicativeExpr
4743 * | AdditiveExpr '+' MultiplicativeExpr
4744 * | AdditiveExpr '-' MultiplicativeExpr
4745 *
4746 * Parse and evaluate an Additive expression, then push the result on the stack
4747 */
4748
4749void
4750xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
4751 xmlXPathEvalMultiplicativeExpr(ctxt);
4752 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004753 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004754 while ((CUR == '+') || (CUR == '-')) {
4755 int plus;
4756
4757 if (CUR == '+') plus = 1;
4758 else plus = 0;
4759 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004760 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004761 xmlXPathEvalMultiplicativeExpr(ctxt);
4762 CHECK_ERROR;
4763 if (plus) xmlXPathAddValues(ctxt);
4764 else xmlXPathSubValues(ctxt);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004765 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004766 }
4767}
4768
4769/**
4770 * xmlXPathEvalRelationalExpr:
4771 * @ctxt: the XPath Parser context
4772 *
4773 * [24] RelationalExpr ::= AdditiveExpr
4774 * | RelationalExpr '<' AdditiveExpr
4775 * | RelationalExpr '>' AdditiveExpr
4776 * | RelationalExpr '<=' AdditiveExpr
4777 * | RelationalExpr '>=' AdditiveExpr
4778 *
4779 * A <= B > C is allowed ? Answer from James, yes with
4780 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
4781 * which is basically what got implemented.
4782 *
4783 * Parse and evaluate a Relational expression, then push the result
4784 * on the stack
4785 */
4786
4787void
4788xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
4789 xmlXPathEvalAdditiveExpr(ctxt);
4790 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004791 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004792 while ((CUR == '<') ||
4793 (CUR == '>') ||
4794 ((CUR == '<') && (NXT(1) == '=')) ||
4795 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004796 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004797
4798 if (CUR == '<') inf = 1;
4799 else inf = 0;
4800 if (NXT(1) == '=') strict = 0;
4801 else strict = 1;
4802 NEXT;
4803 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004804 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004805 xmlXPathEvalAdditiveExpr(ctxt);
4806 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004807 ret = xmlXPathCompareValues(ctxt, inf, strict);
4808 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard55b91f22000-10-05 16:30:11 +00004809 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004810 }
4811}
4812
4813/**
4814 * xmlXPathEvalEqualityExpr:
4815 * @ctxt: the XPath Parser context
4816 *
4817 * [23] EqualityExpr ::= RelationalExpr
4818 * | EqualityExpr '=' RelationalExpr
4819 * | EqualityExpr '!=' RelationalExpr
4820 *
4821 * A != B != C is allowed ? Answer from James, yes with
4822 * (RelationalExpr = RelationalExpr) = RelationalExpr
4823 * (RelationalExpr != RelationalExpr) != RelationalExpr
4824 * which is basically what got implemented.
4825 *
4826 * Parse and evaluate an Equality expression, then push the result on the stack
4827 *
4828 */
4829void
4830xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
4831 xmlXPathEvalRelationalExpr(ctxt);
4832 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004833 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004834 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004835 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004836 int eq, equal;
4837
4838 if (CUR == '=') eq = 1;
4839 else eq = 0;
4840 NEXT;
4841 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004842 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004843 xmlXPathEvalRelationalExpr(ctxt);
4844 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004845 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004846 if (eq) res = xmlXPathNewBoolean(equal);
4847 else res = xmlXPathNewBoolean(!equal);
4848 valuePush(ctxt, res);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004849 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004850 }
4851}
4852
4853/**
4854 * xmlXPathEvalAndExpr:
4855 * @ctxt: the XPath Parser context
4856 *
4857 * [22] AndExpr ::= EqualityExpr
4858 * | AndExpr 'and' EqualityExpr
4859 *
4860 * Parse and evaluate an AND expression, then push the result on the stack
4861 *
4862 */
4863void
4864xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
4865 xmlXPathEvalEqualityExpr(ctxt);
4866 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004867 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00004868 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004869 xmlXPathObjectPtr arg1, arg2;
4870
4871 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004872 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004873 xmlXPathEvalEqualityExpr(ctxt);
4874 CHECK_ERROR;
4875 arg2 = valuePop(ctxt);
4876 arg1 = valuePop(ctxt);
4877 arg1->boolval &= arg2->boolval;
4878 valuePush(ctxt, arg1);
4879 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004880 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004881 }
4882}
4883
4884/**
4885 * xmlXPathEvalExpr:
4886 * @ctxt: the XPath Parser context
4887 *
4888 * [14] Expr ::= OrExpr
4889 * [21] OrExpr ::= AndExpr
4890 * | OrExpr 'or' AndExpr
4891 *
4892 * Parse and evaluate an expression, then push the result on the stack
4893 *
4894 */
4895void
4896xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
4897 xmlXPathEvalAndExpr(ctxt);
4898 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004899 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004900 while ((CUR == 'o') && (NXT(1) == 'r')) {
4901 xmlXPathObjectPtr arg1, arg2;
4902
4903 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004904 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004905 xmlXPathEvalAndExpr(ctxt);
4906 CHECK_ERROR;
4907 arg2 = valuePop(ctxt);
4908 arg1 = valuePop(ctxt);
4909 arg1->boolval |= arg2->boolval;
4910 valuePush(ctxt, arg1);
4911 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004912 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004913 }
4914}
4915
4916/**
4917 * xmlXPathEvaluatePredicateResult:
4918 * @ctxt: the XPath Parser context
4919 * @res: the Predicate Expression evaluation result
4920 * @index: index of the current node in the current list
4921 *
4922 * Evaluate a predicate result for the current node.
4923 * A PredicateExpr is evaluated by evaluating the Expr and converting
4924 * the result to a boolean. If the result is a number, the result will
4925 * be converted to true if the number is equal to the position of the
4926 * context node in the context node list (as returned by the position
4927 * function) and will be converted to false otherwise; if the result
4928 * is not a number, then the result will be converted as if by a call
4929 * to the boolean function.
4930 */
4931int
4932xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004933 xmlXPathObjectPtr res) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004934 if (res == NULL) return(0);
4935 switch (res->type) {
4936 case XPATH_BOOLEAN:
4937 return(res->boolval);
4938 case XPATH_NUMBER:
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004939 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004940 case XPATH_NODESET:
4941 return(res->nodesetval->nodeNr != 0);
4942 case XPATH_STRING:
4943 return((res->stringval != NULL) &&
4944 (xmlStrlen(res->stringval) != 0));
4945 default:
4946 STRANGE
4947 }
4948 return(0);
4949}
4950
4951/**
4952 * xmlXPathEvalPredicate:
4953 * @ctxt: the XPath Parser context
4954 *
4955 * [8] Predicate ::= '[' PredicateExpr ']'
4956 * [9] PredicateExpr ::= Expr
4957 *
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004958 * ---------------------
4959 * For each node in the node-set to be filtered, the PredicateExpr is
4960 * evaluated with that node as the context node, with the number of nodes
4961 * in the node-set as the context size, and with the proximity position
4962 * of the node in the node-set with respect to the axis as the context
4963 * position; if PredicateExpr evaluates to true for that node, the node
4964 * is included in the new node-set; otherwise, it is not included.
4965 * ---------------------
4966 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004967 * Parse and evaluate a predicate for all the elements of the
4968 * current node list. Then refine the list by removing all
4969 * nodes where the predicate is false.
4970 */
4971void
4972xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004973 const xmlChar *cur;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004974 xmlXPathObjectPtr res;
Daniel Veillard740abf52000-10-02 23:04:54 +00004975 xmlXPathObjectPtr obj, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004976 xmlNodeSetPtr newset = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004977 xmlNodeSetPtr oldset;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004978 int i;
4979
Daniel Veillard00fdf371999-10-08 09:40:39 +00004980 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004981 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004982 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004983 }
4984 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004985 SKIP_BLANKS;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004986
4987 /*
4988 * Extract the old set, and then evaluate the result of the
4989 * expression for all the element in the set. use it to grow
4990 * up a new set.
4991 */
Daniel Veillard740abf52000-10-02 23:04:54 +00004992 CHECK_TYPE(XPATH_NODESET);
4993 obj = valuePop(ctxt);
4994 oldset = obj->nodesetval;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004995 ctxt->context->node = NULL;
4996
4997 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004998 ctxt->context->contextSize = 0;
4999 ctxt->context->proximityPosition = 0;
Daniel Veillardff9c3302000-10-13 16:38:25 +00005000 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005001 res = valuePop(ctxt);
5002 if (res != NULL)
5003 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005004 valuePush(ctxt, obj);
Daniel Veillardff9c3302000-10-13 16:38:25 +00005005 CHECK_ERROR;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005006 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005007 /*
5008 * Save the expression pointer since we will have to evaluate
5009 * it multiple times. Initialize the new set.
5010 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005011 cur = ctxt->cur;
5012 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00005013
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005014 for (i = 0; i < oldset->nodeNr; i++) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005015 ctxt->cur = cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00005016
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005017 /*
5018 * Run the evaluation with a node list made of a single item
5019 * in the nodeset.
5020 */
5021 ctxt->context->node = oldset->nodeTab[i];
Daniel Veillard740abf52000-10-02 23:04:54 +00005022 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5023 valuePush(ctxt, tmp);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005024 ctxt->context->contextSize = oldset->nodeNr;
5025 ctxt->context->proximityPosition = i + 1;
Daniel Veillardbe803962000-06-28 23:40:59 +00005026
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005027 xmlXPathEvalExpr(ctxt);
5028 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005029
5030 /*
5031 * The result of the evaluation need to be tested to
5032 * decided whether the filter succeeded or not
5033 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005034 res = valuePop(ctxt);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005035 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
5036 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
5037 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005038
5039 /*
5040 * Cleanup
5041 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005042 if (res != NULL)
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005043 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005044 if (ctxt->value == tmp) {
5045 res = valuePop(ctxt);
5046 xmlXPathFreeObject(res);
5047 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005048
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005049 ctxt->context->node = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005050 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005051
5052 /*
5053 * The result is used as the new evaluation set.
5054 */
Daniel Veillard740abf52000-10-02 23:04:54 +00005055 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005056 ctxt->context->node = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005057 ctxt->context->contextSize = -1;
5058 ctxt->context->proximityPosition = -1;
Daniel Veillard740abf52000-10-02 23:04:54 +00005059 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005060 }
5061 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005062 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005063 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005064
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005065 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005066 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005067#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005068 xmlGenericError(xmlGenericErrorContext, "After predicate : ");
5069 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5070 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005071#endif
5072}
5073
5074/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00005075 * xmlXPathEvalNodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005076 * @ctxt: the XPath Parser context
Daniel Veillard55b91f22000-10-05 16:30:11 +00005077 * @test: pointer to a xmlXPathTestVal
5078 * @type: pointer to a xmlXPathTypeVal
5079 * @prefix: placeholder for a possible name prefix
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005080 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005081 * [7] NodeTest ::= NameTest
5082 * | NodeType '(' ')'
5083 * | 'processing-instruction' '(' Literal ')'
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005084 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005085 * [37] NameTest ::= '*'
5086 * | NCName ':' '*'
5087 * | QName
5088 * [38] NodeType ::= 'comment'
5089 * | 'text'
5090 * | 'processing-instruction'
5091 * | 'node'
5092 *
5093 * Returns the name found and update @test, @type and @prefix appropriately
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005094 */
Daniel Veillard55b91f22000-10-05 16:30:11 +00005095xmlChar *
5096xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
5097 xmlXPathTypeVal *type, xmlChar **prefix, xmlChar *name) {
5098 int blanks;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005099
Daniel Veillard55b91f22000-10-05 16:30:11 +00005100 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
5101 STRANGE;
5102 return(NULL);
5103 }
5104 *type = 0;
5105 *test = 0;
5106 *prefix = NULL;
5107 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005108
Daniel Veillard55b91f22000-10-05 16:30:11 +00005109 if ((name == NULL) && (CUR == '*')) {
5110 /*
5111 * All elements
5112 */
5113 NEXT;
5114 *test = NODE_TEST_ALL;
5115 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005116 }
5117
Daniel Veillard55b91f22000-10-05 16:30:11 +00005118 if (name == NULL)
5119 name = xmlXPathParseNCName(ctxt);
5120 if (name == NULL) {
5121 XP_ERROR0(XPATH_EXPR_ERROR);
5122 }
5123
5124 blanks = IS_BLANK(CUR);
5125 SKIP_BLANKS;
5126 if (CUR == '(') {
5127 NEXT;
5128 /*
5129 * NodeType or PI search
5130 */
5131 if (xmlStrEqual(name, BAD_CAST "comment"))
5132 *type = NODE_TYPE_COMMENT;
5133 else if (xmlStrEqual(name, BAD_CAST "node"))
5134 *type = NODE_TYPE_NODE;
5135 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5136 *type = NODE_TYPE_PI;
5137 else if (xmlStrEqual(name, BAD_CAST "text"))
5138 *type = NODE_TYPE_TEXT;
5139 else
5140 XP_ERROR0(XPATH_EXPR_ERROR);
5141
5142 *test = NODE_TEST_TYPE;
5143
5144 SKIP_BLANKS;
5145 if (*type == NODE_TYPE_PI) {
5146 /*
5147 * Specific case: search a PI by name.
5148 */
5149 xmlXPathObjectPtr cur;
5150
5151 if (name != NULL)
5152 xmlFree(name);
5153
5154 xmlXPathEvalLiteral(ctxt);
5155 CHECK_ERROR 0;
5156 xmlXPathStringFunction(ctxt, 1);
5157 CHECK_ERROR0;
5158 cur = valuePop(ctxt);
5159 name = xmlStrdup(cur->stringval);
5160 xmlXPathFreeObject(cur);
5161 SKIP_BLANKS;
5162 }
5163 if (CUR != ')')
5164 XP_ERROR0(XPATH_UNCLOSED_ERROR);
5165 NEXT;
5166 return(name);
5167 }
5168 *test = NODE_TEST_NAME;
5169 if ((!blanks) && (CUR == ':')) {
5170 NEXT;
5171
5172 *prefix = name;
5173
5174 if (CUR == '*') {
5175 /*
5176 * All elements
5177 */
5178 NEXT;
5179 *test = NODE_TEST_ALL;
5180 return(NULL);
5181 }
5182
5183 name = xmlXPathParseNCName(ctxt);
5184 if (name == NULL) {
5185 XP_ERROR0(XPATH_EXPR_ERROR);
5186 }
5187 }
5188 return(name);
5189}
5190
5191/**
5192 * xmlXPathIsAxisName:
5193 * @name: a preparsed name token
5194 *
5195 * [6] AxisName ::= 'ancestor'
5196 * | 'ancestor-or-self'
5197 * | 'attribute'
5198 * | 'child'
5199 * | 'descendant'
5200 * | 'descendant-or-self'
5201 * | 'following'
5202 * | 'following-sibling'
5203 * | 'namespace'
5204 * | 'parent'
5205 * | 'preceding'
5206 * | 'preceding-sibling'
5207 * | 'self'
5208 *
5209 * Returns the axis or 0
5210 */
5211xmlXPathAxisVal
5212xmlXPathIsAxisName(const xmlChar *name) {
5213 xmlXPathAxisVal ret = 0;
5214 switch (name[0]) {
5215 case 'a':
5216 if (xmlStrEqual(name, BAD_CAST "ancestor"))
5217 ret = AXIS_ANCESTOR;
5218 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
5219 ret = AXIS_ANCESTOR_OR_SELF;
5220 if (xmlStrEqual(name, BAD_CAST "attribute"))
5221 ret = AXIS_ATTRIBUTE;
5222 break;
5223 case 'c':
5224 if (xmlStrEqual(name, BAD_CAST "child"))
5225 ret = AXIS_CHILD;
5226 break;
5227 case 'd':
5228 if (xmlStrEqual(name, BAD_CAST "descendant"))
5229 ret = AXIS_DESCENDANT;
5230 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
5231 ret = AXIS_DESCENDANT_OR_SELF;
5232 break;
5233 case 'f':
5234 if (xmlStrEqual(name, BAD_CAST "following"))
5235 ret = AXIS_FOLLOWING;
5236 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
5237 ret = AXIS_FOLLOWING_SIBLING;
5238 break;
5239 case 'n':
5240 if (xmlStrEqual(name, BAD_CAST "namespace"))
5241 ret = AXIS_NAMESPACE;
5242 break;
5243 case 'p':
5244 if (xmlStrEqual(name, BAD_CAST "parent"))
5245 ret = AXIS_PARENT;
5246 if (xmlStrEqual(name, BAD_CAST "preceding"))
5247 ret = AXIS_PRECEDING;
5248 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
5249 ret = AXIS_PRECEDING_SIBLING;
5250 break;
5251 case 's':
5252 if (xmlStrEqual(name, BAD_CAST "self"))
5253 ret = AXIS_SELF;
5254 break;
5255 }
5256 return(ret);
5257}
5258
5259/**
5260 * xmlXPathEvalAxisSpecifier:
5261 * @ctxt: the XPath Parser context
5262 *
5263 *
5264 * Returns the axis found
5265 */
5266xmlXPathAxisVal
5267xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
5268 xmlXPathAxisVal ret = AXIS_CHILD;
5269 int blank = 0;
5270 xmlChar *name;
5271
5272 if (CUR == '@') {
5273 NEXT;
5274 return(AXIS_ATTRIBUTE);
5275 } else {
5276 name = xmlXPathParseNCName(ctxt);
5277 if (name == NULL) {
5278 XP_ERROR0(XPATH_EXPR_ERROR);
5279 }
5280 if (IS_BLANK(CUR))
5281 blank = 1;
5282 SKIP_BLANKS;
5283 if ((CUR == ':') && (NXT(1) == ':')) {
5284 ret = xmlXPathIsAxisName(name);
5285 } else if ((blank) && (CUR == ':'))
5286 XP_ERROR0(XPATH_EXPR_ERROR);
5287
5288 xmlFree(name);
5289 }
5290 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005291}
5292
5293/**
5294 * xmlXPathEvalStep:
5295 * @ctxt: the XPath Parser context
5296 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005297 * [4] Step ::= AxisSpecifier NodeTest Predicate*
5298 * | AbbreviatedStep
Daniel Veillardac260302000-10-04 13:33:43 +00005299 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005300 * [12] AbbreviatedStep ::= '.' | '..'
5301 *
5302 * [5] AxisSpecifier ::= AxisName '::'
5303 * | AbbreviatedAxisSpecifier
5304 *
5305 * [13] AbbreviatedAxisSpecifier ::= '@'?
Daniel Veillardac260302000-10-04 13:33:43 +00005306 *
5307 * Modified for XPtr range support as:
5308 *
5309 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5310 * | AbbreviatedStep
5311 * | 'range-to' '(' Expr ')' Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005312 *
5313 * Evaluate one step in a Location Path
5314 * A location step of . is short for self::node(). This is
5315 * particularly useful in conjunction with //. For example, the
5316 * location path .//para is short for
5317 * self::node()/descendant-or-self::node()/child::para
5318 * and so will select all para descendant elements of the context
5319 * node.
5320 * Similarly, a location step of .. is short for parent::node().
5321 * For example, ../title is short for parent::node()/child::title
5322 * and so will select the title children of the parent of the context
5323 * node.
5324 */
5325void
5326xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005327 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005328 if ((CUR == '.') && (NXT(1) == '.')) {
5329 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005330 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005331 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
Daniel Veillard767662d2000-10-27 17:04:52 +00005332 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005333 } else if (CUR == '.') {
5334 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005335 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005336 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005337 xmlChar *name = NULL;
5338 xmlChar *prefix = NULL;
5339 xmlXPathTestVal test;
5340 xmlXPathAxisVal axis;
5341 xmlXPathTypeVal type;
5342
5343 /*
5344 * The modification needed for XPointer change to the production
5345 */
Daniel Veillardac260302000-10-04 13:33:43 +00005346#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard55b91f22000-10-05 16:30:11 +00005347 if (ctxt->context->xptr) {
5348 name = xmlXPathParseNCName(ctxt);
5349 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
5350 xmlFree(name);
5351 SKIP_BLANKS;
5352 if (CUR != '(') {
5353 XP_ERROR(XPATH_EXPR_ERROR);
5354 }
5355 NEXT;
5356 SKIP_BLANKS;
Daniel Veillardac260302000-10-04 13:33:43 +00005357
Daniel Veillard55b91f22000-10-05 16:30:11 +00005358 xmlXPtrRangeToFunction(ctxt, 1);
Daniel Veillardac260302000-10-04 13:33:43 +00005359 CHECK_ERROR;
5360
Daniel Veillard55b91f22000-10-05 16:30:11 +00005361 SKIP_BLANKS;
5362 if (CUR != ')') {
5363 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardac260302000-10-04 13:33:43 +00005364 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005365 NEXT;
5366 goto eval_predicates;
Daniel Veillardac260302000-10-04 13:33:43 +00005367 }
Daniel Veillardac260302000-10-04 13:33:43 +00005368 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005369#endif
5370 if (name == NULL)
5371 name = xmlXPathParseNCName(ctxt);
5372 if (name != NULL) {
5373 axis = xmlXPathIsAxisName(name);
5374 if (axis != 0) {
5375 SKIP_BLANKS;
5376 if ((CUR == ':') && (NXT(1) == ':')) {
5377 SKIP(2);
5378 xmlFree(name);
5379 name = NULL;
5380 } else {
5381 /* an element name can conflict with an axis one :-\ */
5382 axis = AXIS_CHILD;
5383 }
5384 } else {
5385 axis = AXIS_CHILD;
5386 }
5387 } else if (CUR == '@') {
5388 NEXT;
5389 axis = AXIS_ATTRIBUTE;
5390 } else {
5391 axis = AXIS_CHILD;
5392 }
5393
5394 CHECK_ERROR;
5395
5396 name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
5397 if (test == 0)
5398 return;
5399
5400#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005401 xmlGenericError(xmlGenericErrorContext,
5402 "Basis : computing new set\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005403#endif
5404 xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
5405#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005406 xmlGenericError(xmlGenericErrorContext, "Basis : ");
5407 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005408#endif
5409 if (name != NULL)
5410 xmlFree(name);
5411 if (prefix != NULL)
5412 xmlFree(prefix);
5413
5414eval_predicates:
Daniel Veillard00fdf371999-10-08 09:40:39 +00005415 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005416 while (CUR == '[') {
5417 xmlXPathEvalPredicate(ctxt);
5418 }
5419 }
5420#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005421 xmlGenericError(xmlGenericErrorContext, "Step : ");
5422 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5423 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005424#endif
5425}
5426
5427/**
5428 * xmlXPathEvalRelativeLocationPath:
5429 * @ctxt: the XPath Parser context
5430 *
5431 * [3] RelativeLocationPath ::= Step
5432 * | RelativeLocationPath '/' Step
5433 * | AbbreviatedRelativeLocationPath
5434 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
5435 *
5436 */
5437void
5438xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005439 SKIP_BLANKS;
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00005440 if ((CUR == '/') && (NXT(1) == '/')) {
5441 SKIP(2);
5442 SKIP_BLANKS;
5443 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00005444 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00005445 } else if (CUR == '/') {
5446 NEXT;
5447 SKIP_BLANKS;
5448 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005449 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005450 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005451 while (CUR == '/') {
5452 if ((CUR == '/') && (NXT(1) == '/')) {
5453 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005454 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005455 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00005456 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005457 xmlXPathEvalStep(ctxt);
5458 } else if (CUR == '/') {
5459 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005460 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005461 xmlXPathEvalStep(ctxt);
5462 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005463 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005464 }
5465}
5466
5467/**
5468 * xmlXPathEvalLocationPath:
5469 * @ctxt: the XPath Parser context
5470 *
5471 * [1] LocationPath ::= RelativeLocationPath
5472 * | AbsoluteLocationPath
5473 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
5474 * | AbbreviatedAbsoluteLocationPath
5475 * [10] AbbreviatedAbsoluteLocationPath ::=
5476 * '//' RelativeLocationPath
5477 *
5478 * // is short for /descendant-or-self::node()/. For example,
5479 * //para is short for /descendant-or-self::node()/child::para and
5480 * so will select any para element in the document (even a para element
5481 * that is a document element will be selected by //para since the
5482 * document element node is a child of the root node); div//para is
5483 * short for div/descendant-or-self::node()/child::para and so will
5484 * select all para descendants of div children.
5485 */
5486void
5487xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005488 SKIP_BLANKS;
5489 if (CUR != '/') {
5490 xmlXPathEvalRelativeLocationPath(ctxt);
5491 } else {
5492 while (CUR == '/') {
5493 if ((CUR == '/') && (NXT(1) == '/')) {
5494 SKIP(2);
5495 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005496 xmlXPathNodeCollectAndTest(ctxt,
Daniel Veillard00fdf371999-10-08 09:40:39 +00005497 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
Daniel Veillard767662d2000-10-27 17:04:52 +00005498 NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005499 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005500 } else if (CUR == '/') {
5501 NEXT;
5502 SKIP_BLANKS;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005503 if (CUR != 0)
5504 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005505 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005506 }
5507 }
5508}
5509
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005510/**
5511 * xmlXPathEval:
5512 * @str: the XPath expression
Daniel Veillard740abf52000-10-02 23:04:54 +00005513 * @ctx: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005514 *
5515 * Evaluate the XPath Location Path in the given context.
5516 *
5517 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
5518 * the caller has to free the object.
5519 */
5520xmlXPathObjectPtr
Daniel Veillard740abf52000-10-02 23:04:54 +00005521xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
5522 xmlXPathParserContextPtr ctxt;
Daniel Veillard41e06512000-11-13 11:47:47 +00005523 xmlXPathObjectPtr res = NULL, tmp, init = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005524 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005525
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005526 xmlXPathInit();
5527
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00005528 CHECK_CONTEXT(ctx)
5529
Daniel Veillard740abf52000-10-02 23:04:54 +00005530 ctxt = xmlXPathNewParserContext(str, ctx);
Daniel Veillard41e06512000-11-13 11:47:47 +00005531 if (ctx->node != NULL) {
5532 init = xmlXPathNewNodeSet(ctx->node);
5533 valuePush(ctxt, init);
5534 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005535 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005536
Daniel Veillard767662d2000-10-27 17:04:52 +00005537 if (ctxt->value == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005538 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard767662d2000-10-27 17:04:52 +00005539 "xmlXPathEval: evaluation failed\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00005540 } else {
5541 res = valuePop(ctxt);
5542 }
5543
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005544 do {
Daniel Veillard740abf52000-10-02 23:04:54 +00005545 tmp = valuePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005546 if (tmp != NULL) {
Daniel Veillard41e06512000-11-13 11:47:47 +00005547 if (tmp != init)
5548 stack++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005549 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005550 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005551 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005552 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005553 xmlGenericError(xmlGenericErrorContext,
5554 "xmlXPathEval: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005555 stack);
5556 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005557 if (ctxt->error != XPATH_EXPRESSION_OK) {
5558 xmlXPathFreeObject(res);
5559 res = NULL;
5560 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005561
Daniel Veillard740abf52000-10-02 23:04:54 +00005562 xmlXPathFreeParserContext(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005563 return(res);
5564}
5565
5566/**
5567 * xmlXPathEvalExpression:
5568 * @str: the XPath expression
5569 * @ctxt: the XPath context
5570 *
5571 * Evaluate the XPath expression in the given context.
5572 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00005573 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005574 * the caller has to free the object.
5575 */
5576xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005577xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005578 xmlXPathParserContextPtr pctxt;
5579 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005580 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005581
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005582 xmlXPathInit();
5583
Daniel Veillard740abf52000-10-02 23:04:54 +00005584 CHECK_CONTEXT(ctxt)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005585
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005586 pctxt = xmlXPathNewParserContext(str, ctxt);
5587 xmlXPathEvalExpr(pctxt);
5588
5589 res = valuePop(pctxt);
5590 do {
5591 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005592 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005593 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005594 stack++;
5595 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005596 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005597 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005598 xmlGenericError(xmlGenericErrorContext,
5599 "xmlXPathEvalExpression: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005600 stack);
5601 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005602 xmlXPathFreeParserContext(pctxt);
5603 return(res);
5604}
5605
Daniel Veillard52afe802000-10-22 16:56:02 +00005606void
5607xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
5608{
5609 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
5610 xmlXPathBooleanFunction);
5611 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
5612 xmlXPathCeilingFunction);
5613 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
5614 xmlXPathCountFunction);
5615 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
5616 xmlXPathConcatFunction);
5617 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
5618 xmlXPathContainsFunction);
5619 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
5620 xmlXPathIdFunction);
5621 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
5622 xmlXPathFalseFunction);
5623 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
5624 xmlXPathFloorFunction);
5625 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
5626 xmlXPathLastFunction);
5627 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
5628 xmlXPathLangFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00005629 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
5630 xmlXPathLocalNameFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00005631 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
5632 xmlXPathNotFunction);
5633 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
5634 xmlXPathNameFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00005635 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
5636 xmlXPathNamespaceURIFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00005637 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
5638 xmlXPathNormalizeFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00005639 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
5640 xmlXPathNumberFunction);
5641 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
5642 xmlXPathPositionFunction);
5643 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
5644 xmlXPathRoundFunction);
5645 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
5646 xmlXPathStringFunction);
5647 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
5648 xmlXPathStringLengthFunction);
5649 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
5650 xmlXPathStartsWithFunction);
5651 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
5652 xmlXPathSubstringFunction);
5653 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
5654 xmlXPathSubstringBeforeFunction);
5655 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
5656 xmlXPathSubstringAfterFunction);
5657 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
5658 xmlXPathSumFunction);
5659 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
5660 xmlXPathTrueFunction);
5661 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
5662 xmlXPathTranslateFunction);
5663}
5664
Daniel Veillard361d8452000-04-03 19:48:13 +00005665#endif /* LIBXML_XPATH_ENABLED */