blob: 1ea8aea60b8ff3404579c689bdd02d0055f5ae0b [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 Veillardac260302000-10-04 13:33:43 +00004 * designed to be used by both XSLT and XPtr.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
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 Veillard361d8452000-04-03 19:48:13 +000022#include "xmlversion.h"
23#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>
51#include <libxml/parserInternals.h>
Daniel Veillardac260302000-10-04 13:33:43 +000052#ifdef LIBXML_XPTR_ENABLED
53#include <libxml/xpointer.h>
54#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +000055
Daniel Veillarddbfd6411999-12-28 16:35:14 +000056/* #define DEBUG */
57/* #define DEBUG_STEP */
58/* #define DEBUG_EXPR */
59
Daniel Veillard1566d3a1999-07-15 14:24:29 +000060/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000061 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000062 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000063 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000064double xmlXPathNAN = 0;
65double xmlXPathPINF = 1;
66double xmlXPathMINF = -1;
67
Daniel Veillardb05deb71999-08-10 19:04:08 +000068#ifndef isinf
69#ifndef HAVE_ISINF
70
71#if HAVE_FPCLASS
72
73int isinf(double d) {
74 fpclass_t type = fpclass(d);
75 switch (type) {
76 case FP_NINF:
77 return(-1);
78 case FP_PINF:
79 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000080 }
81 return(0);
82}
83
84#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
85
86#if HAVE_FP_CLASS_H
87#include <fp_class.h>
88#endif
89
90int isinf(double d) {
91#if HAVE_FP_CLASS
92 int fpclass = fp_class(d);
93#else
94 int fpclass = fp_class_d(d);
95#endif
96 if (fpclass == FP_POS_INF)
97 return(1);
98 if (fpclass == FP_NEG_INF)
99 return(-1);
100 return(0);
101}
102
103#elif defined(HAVE_CLASS)
104
105int isinf(double d) {
106 int fpclass = class(d);
107 if (fpclass == FP_PLUS_INF)
108 return(1);
109 if (fpclass == FP_MINUS_INF)
110 return(-1);
111 return(0);
112}
113#elif defined(finite) || defined(HAVE_FINITE)
114int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000115#elif defined(HUGE_VAL)
Daniel Veillardfc708e22000-04-08 13:17:27 +0000116int isinf(double x)
Daniel Veillard991e63d1999-08-15 23:32:28 +0000117{
118 if (x == HUGE_VAL)
119 return(1);
120 if (x == -HUGE_VAL)
121 return(-1);
122 return(0);
123}
124#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000125
126#endif /* ! HAVE_ISINF */
127#endif /* ! defined(isinf) */
128
129#ifndef isnan
130#ifndef HAVE_ISNAN
131
132#ifdef HAVE_ISNAND
133#define isnan(f) isnand(f)
134#endif /* HAVE_iSNAND */
135
136#endif /* ! HAVE_iSNAN */
137#endif /* ! defined(isnan) */
138
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000139/**
140 * xmlXPathInit:
141 *
142 * Initialize the XPath environment
143 */
144void
145xmlXPathInit(void) {
146 static int initialized = 0;
147
148 if (initialized) return;
149
150 xmlXPathNAN = 0;
151 xmlXPathNAN /= 0;
152
153 xmlXPathPINF = 1;
154 xmlXPathPINF /= 0;
155
156 xmlXPathMINF = -1;
157 xmlXPathMINF /= 0;
158
159 initialized = 1;
160}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000161
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000162FILE *xmlXPathDebug = NULL;
163
164#define TODO \
165 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
166 __FILE__, __LINE__);
167
168#define STRANGE \
169 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
170 __FILE__, __LINE__);
171
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000172double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000173void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000174
175/************************************************************************
176 * *
177 * Parser stacks related functions and macros *
178 * *
179 ************************************************************************/
180
181/*
182 * Generic function for accessing stacks in the Parser Context
183 */
184
185#define PUSH_AND_POP(type, name) \
186extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
187 if (ctxt->name##Nr >= ctxt->name##Max) { \
188 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000189 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000190 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
191 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000192 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000193 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000194 } \
195 } \
196 ctxt->name##Tab[ctxt->name##Nr] = value; \
197 ctxt->name = value; \
198 return(ctxt->name##Nr++); \
199} \
200extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
201 type ret; \
202 if (ctxt->name##Nr <= 0) return(0); \
203 ctxt->name##Nr--; \
204 if (ctxt->name##Nr > 0) \
205 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
206 else \
207 ctxt->name = NULL; \
208 ret = ctxt->name##Tab[ctxt->name##Nr]; \
209 ctxt->name##Tab[ctxt->name##Nr] = 0; \
210 return(ret); \
211} \
212
213PUSH_AND_POP(xmlXPathObjectPtr, value)
214
215/*
216 * Macros for accessing the content. Those should be used only by the parser,
217 * and not exported.
218 *
219 * Dirty macros, i.e. one need to make assumption on the context to use them
220 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000221 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000222 * CUR returns the current xmlChar value, i.e. a 8 bit value
223 * in ISO-Latin or UTF-8.
224 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000225 * only to compare to ASCII values otherwise it would break when
226 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000227 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000228 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000229 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000230 * strings within the parser.
231 * CURRENT Returns the current char value, with the full decoding of
232 * UTF-8 if we are using this mode. It returns an int.
233 * NEXT Skip to the next character, this does the proper decoding
234 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000235 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000236 */
237
238#define CUR (*ctxt->cur)
239#define SKIP(val) ctxt->cur += (val)
240#define NXT(val) ctxt->cur[(val)]
241#define CUR_PTR ctxt->cur
242
243#define SKIP_BLANKS \
244 while (IS_BLANK(*(ctxt->cur))) NEXT
245
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000246#define CURRENT (*ctxt->cur)
247#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000248
249/************************************************************************
250 * *
251 * Error handling routines *
252 * *
253 ************************************************************************/
254
255#define XPATH_EXPRESSION_OK 0
256#define XPATH_NUMBER_ERROR 1
257#define XPATH_UNFINISHED_LITERAL_ERROR 2
258#define XPATH_START_LITERAL_ERROR 3
259#define XPATH_VARIABLE_REF_ERROR 4
260#define XPATH_UNDEF_VARIABLE_ERROR 5
261#define XPATH_INVALID_PREDICATE_ERROR 6
262#define XPATH_EXPR_ERROR 7
263#define XPATH_UNCLOSED_ERROR 8
264#define XPATH_UNKNOWN_FUNC_ERROR 9
265#define XPATH_INVALID_OPERAND 10
266#define XPATH_INVALID_TYPE 11
267#define XPATH_INVALID_ARITY 12
Daniel Veillardf09e7e32000-10-01 15:53:30 +0000268#define XPATH_INVALID_CTXT_SIZE 13
269#define XPATH_INVALID_CTXT_POSITION 14
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000270
271const char *xmlXPathErrorMessages[] = {
272 "Ok",
273 "Number encoding",
274 "Unfinished litteral",
275 "Start of litteral",
276 "Expected $ for variable reference",
277 "Undefined variable",
278 "Invalid predicate",
279 "Invalid expression",
280 "Missing closing curly brace",
281 "Unregistered function",
282 "Invalid operand",
283 "Invalid type",
284 "Invalid number of arguments",
Daniel Veillardf09e7e32000-10-01 15:53:30 +0000285 "Invalid context size",
286 "Invalid context position",
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000287};
288
289/**
290 * xmlXPathError:
291 * @ctxt: the XPath Parser context
292 * @file: the file name
293 * @line: the line number
294 * @no: the error number
295 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000296 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000297 *
298 * Returns the newly created object.
299 */
300void
301xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
302 int line, int no) {
303 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000304 const xmlChar *cur;
305 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000306
307 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
308 xmlXPathErrorMessages[no]);
309
310 cur = ctxt->cur;
311 base = ctxt->base;
312 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
313 cur--;
314 }
315 n = 0;
316 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
317 cur--;
318 if ((*cur == '\n') || (*cur == '\r')) cur++;
319 base = cur;
320 n = 0;
321 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
322 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
323 n++;
324 }
325 fprintf(xmlXPathDebug, "\n");
326 cur = ctxt->cur;
327 while ((*cur == '\n') || (*cur == '\r'))
328 cur--;
329 n = 0;
330 while ((cur != base) && (n++ < 80)) {
331 fprintf(xmlXPathDebug, " ");
332 base++;
333 }
334 fprintf(xmlXPathDebug,"^\n");
335}
336
337#define CHECK_ERROR \
338 if (ctxt->error != XPATH_EXPRESSION_OK) return
339
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000340#define XP_ERROR(X) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000341 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
342 ctxt->error = (X); return; }
343
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000344#define XP_ERROR0(X) \
Daniel Veillard991e63d1999-08-15 23:32:28 +0000345 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
346 ctxt->error = (X); return(0); }
347
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000348#define CHECK_TYPE(typeval) \
349 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000350 XP_ERROR(XPATH_INVALID_TYPE) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000351
352
353/************************************************************************
354 * *
355 * Routines to handle NodeSets *
356 * *
357 ************************************************************************/
358
359#define XML_NODESET_DEFAULT 10
360/**
361 * xmlXPathNodeSetCreate:
362 * @val: an initial xmlNodePtr, or NULL
363 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000364 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000365 *
366 * Returns the newly created object.
367 */
368xmlNodeSetPtr
369xmlXPathNodeSetCreate(xmlNodePtr val) {
370 xmlNodeSetPtr ret;
371
Daniel Veillard6454aec1999-09-02 22:04:43 +0000372 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000373 if (ret == NULL) {
374 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
375 return(NULL);
376 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000377 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000378 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000379 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000380 sizeof(xmlNodePtr));
381 if (ret->nodeTab == NULL) {
382 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
383 return(NULL);
384 }
385 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000386 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000387 ret->nodeMax = XML_NODESET_DEFAULT;
388 ret->nodeTab[ret->nodeNr++] = val;
389 }
390 return(ret);
391}
392
393/**
394 * xmlXPathNodeSetAdd:
395 * @cur: the initial node set
396 * @val: a new xmlNodePtr
397 *
398 * add a new xmlNodePtr ot an existing NodeSet
399 */
400void
401xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
402 int i;
403
404 if (val == NULL) return;
405
406 /*
407 * check against doublons
408 */
409 for (i = 0;i < cur->nodeNr;i++)
410 if (cur->nodeTab[i] == val) return;
411
412 /*
413 * grow the nodeTab if needed
414 */
415 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000416 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000417 sizeof(xmlNodePtr));
418 if (cur->nodeTab == NULL) {
419 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
420 return;
421 }
422 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000423 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000424 cur->nodeMax = XML_NODESET_DEFAULT;
425 } else if (cur->nodeNr == cur->nodeMax) {
426 xmlNodePtr *temp;
427
428 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000429 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000430 sizeof(xmlNodePtr));
431 if (temp == NULL) {
432 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
433 return;
434 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000435 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000436 }
437 cur->nodeTab[cur->nodeNr++] = val;
438}
439
440/**
441 * xmlXPathNodeSetMerge:
442 * @val1: the first NodeSet
443 * @val2: the second NodeSet
444 *
445 * Merges two nodesets, all nodes from @val2 are added to @val1
446 *
447 * Returns val1 once extended or NULL in case of error.
448 */
449xmlNodeSetPtr
450xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
451 int i;
452
453 if (val1 == NULL) return(NULL);
454 if (val2 == NULL) return(val1);
455
456 /*
457 * !!!!! this can be optimized a lot, knowing that both
458 * val1 and val2 already have unicity of their values.
459 */
460
461 for (i = 0;i < val2->nodeNr;i++)
462 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
463
464 return(val1);
465}
466
467/**
468 * xmlXPathNodeSetDel:
469 * @cur: the initial node set
470 * @val: an xmlNodePtr
471 *
472 * Removes an xmlNodePtr from an existing NodeSet
473 */
474void
475xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
476 int i;
477
478 if (cur == NULL) return;
479 if (val == NULL) return;
480
481 /*
482 * check against doublons
483 */
484 for (i = 0;i < cur->nodeNr;i++)
485 if (cur->nodeTab[i] == val) break;
486
487 if (i >= cur->nodeNr) {
488#ifdef DEBUG
489 fprintf(xmlXPathDebug,
490 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
491 val->name);
492#endif
493 return;
494 }
495 cur->nodeNr--;
496 for (;i < cur->nodeNr;i++)
497 cur->nodeTab[i] = cur->nodeTab[i + 1];
498 cur->nodeTab[cur->nodeNr] = NULL;
499}
500
501/**
502 * xmlXPathNodeSetRemove:
503 * @cur: the initial node set
504 * @val: the index to remove
505 *
506 * Removes an entry from an existing NodeSet list.
507 */
508void
509xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
510 if (cur == NULL) return;
511 if (val >= cur->nodeNr) return;
512 cur->nodeNr--;
513 for (;val < cur->nodeNr;val++)
514 cur->nodeTab[val] = cur->nodeTab[val + 1];
515 cur->nodeTab[cur->nodeNr] = NULL;
516}
517
518/**
519 * xmlXPathFreeNodeSet:
520 * @obj: the xmlNodeSetPtr to free
521 *
522 * Free the NodeSet compound (not the actual nodes !).
523 */
524void
525xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
526 if (obj == NULL) return;
527 if (obj->nodeTab != NULL) {
528#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000529 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000530#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000531 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000532 }
533#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000534 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000535#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000536 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000537}
538
Daniel Veillardb96e6431999-08-29 21:02:19 +0000539#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000540/**
541 * xmlXPathDebugNodeSet:
542 * @output: a FILE * for the output
543 * @obj: the xmlNodeSetPtr to free
544 *
545 * Quick display of a NodeSet
546 */
547void
548xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
549 int i;
550
551 if (output == NULL) output = xmlXPathDebug;
552 if (obj == NULL) {
553 fprintf(output, "NodeSet == NULL !\n");
554 return;
555 }
556 if (obj->nodeNr == 0) {
557 fprintf(output, "NodeSet is empty\n");
558 return;
559 }
560 if (obj->nodeTab == NULL) {
561 fprintf(output, " nodeTab == NULL !\n");
562 return;
563 }
564 for (i = 0; i < obj->nodeNr; i++) {
565 if (obj->nodeTab[i] == NULL) {
566 fprintf(output, " NULL !\n");
567 return;
568 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000569 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
570 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000571 fprintf(output, " /");
572 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000573 fprintf(output, " noname!");
574 else fprintf(output, " %s", obj->nodeTab[i]->name);
575 }
576 fprintf(output, "\n");
577}
578#endif
579
580/************************************************************************
581 * *
582 * Routines to handle Variable *
583 * *
584 * UNIMPLEMENTED CURRENTLY *
585 * *
586 ************************************************************************/
587
588/**
589 * xmlXPathVariablelookup:
590 * @ctxt: the XPath Parser context
591 * @prefix: the variable name namespace if any
592 * @name: the variable name
593 *
594 * Search in the Variable array of the context for the given
595 * variable value.
596 *
597 * UNIMPLEMENTED: always return NULL.
598 *
599 * Returns the value or NULL if not found
600 */
601xmlXPathObjectPtr
602xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000603 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000604 return(NULL);
605}
606
607/************************************************************************
608 * *
609 * Routines to handle Values *
610 * *
611 ************************************************************************/
612
613/* Allocations are terrible, one need to optimize all this !!! */
614
615/**
616 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000617 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000618 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000619 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000620 *
621 * Returns the newly created object.
622 */
623xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000624xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000625 xmlXPathObjectPtr ret;
626
Daniel Veillard6454aec1999-09-02 22:04:43 +0000627 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000628 if (ret == NULL) {
629 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
630 return(NULL);
631 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000632 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000633 ret->type = XPATH_NUMBER;
634 ret->floatval = val;
635 return(ret);
636}
637
638/**
639 * xmlXPathNewBoolean:
640 * @val: the boolean value
641 *
642 * Create a new xmlXPathObjectPtr of type boolean and of value @val
643 *
644 * Returns the newly created object.
645 */
646xmlXPathObjectPtr
647xmlXPathNewBoolean(int val) {
648 xmlXPathObjectPtr ret;
649
Daniel Veillard6454aec1999-09-02 22:04:43 +0000650 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000651 if (ret == NULL) {
Daniel Veillard740abf52000-10-02 23:04:54 +0000652 fprintf(xmlXPathDebug, "xmlXPathNewBoolean: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000653 return(NULL);
654 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000655 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000656 ret->type = XPATH_BOOLEAN;
657 ret->boolval = (val != 0);
658 return(ret);
659}
660
661/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000662 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000663 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000664 *
665 * Create a new xmlXPathObjectPtr of type string and of value @val
666 *
667 * Returns the newly created object.
668 */
669xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000670xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000671 xmlXPathObjectPtr ret;
672
Daniel Veillard6454aec1999-09-02 22:04:43 +0000673 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000674 if (ret == NULL) {
Daniel Veillard740abf52000-10-02 23:04:54 +0000675 fprintf(xmlXPathDebug, "xmlXPathNewString: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000676 return(NULL);
677 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000678 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000679 ret->type = XPATH_STRING;
680 ret->stringval = xmlStrdup(val);
681 return(ret);
682}
683
684/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000685 * xmlXPathNewCString:
686 * @val: the char * value
687 *
688 * Create a new xmlXPathObjectPtr of type string and of value @val
689 *
690 * Returns the newly created object.
691 */
692xmlXPathObjectPtr
693xmlXPathNewCString(const char *val) {
694 xmlXPathObjectPtr ret;
695
Daniel Veillard6454aec1999-09-02 22:04:43 +0000696 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000697 if (ret == NULL) {
Daniel Veillard740abf52000-10-02 23:04:54 +0000698 fprintf(xmlXPathDebug, "xmlXPathNewCString: out of memory\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000699 return(NULL);
700 }
701 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
702 ret->type = XPATH_STRING;
703 ret->stringval = xmlStrdup(BAD_CAST val);
704 return(ret);
705}
706
707/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000708 * xmlXPathNewNodeSet:
709 * @val: the NodePtr value
710 *
711 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
712 * it with the single Node @val
713 *
714 * Returns the newly created object.
715 */
716xmlXPathObjectPtr
717xmlXPathNewNodeSet(xmlNodePtr val) {
718 xmlXPathObjectPtr ret;
719
Daniel Veillard6454aec1999-09-02 22:04:43 +0000720 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000721 if (ret == NULL) {
Daniel Veillard740abf52000-10-02 23:04:54 +0000722 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000723 return(NULL);
724 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000725 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000726 ret->type = XPATH_NODESET;
727 ret->nodesetval = xmlXPathNodeSetCreate(val);
728 return(ret);
729}
730
731/**
732 * xmlXPathNewNodeSetList:
733 * @val: an existing NodeSet
734 *
735 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
736 * it with the Nodeset @val
737 *
738 * Returns the newly created object.
739 */
740xmlXPathObjectPtr
741xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
742 xmlXPathObjectPtr ret;
Daniel Veillardbe803962000-06-28 23:40:59 +0000743 int i;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000744
Daniel Veillardbe803962000-06-28 23:40:59 +0000745 if (val == NULL)
746 ret = NULL;
747 else if (val->nodeTab == NULL)
748 ret = xmlXPathNewNodeSet(NULL);
749 else
750 {
751 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
752 for (i = 1; i < val->nodeNr; ++i)
753 xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
754 }
755
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000756 return(ret);
757}
758
759/**
Daniel Veillard740abf52000-10-02 23:04:54 +0000760 * xmlXPathWrapNodeSet:
761 * @val: the NodePtr value
762 *
763 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
764 *
765 * Returns the newly created object.
766 */
767xmlXPathObjectPtr
768xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
769 xmlXPathObjectPtr ret;
770
771 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
772 if (ret == NULL) {
773 fprintf(xmlXPathDebug, "xmlXPathWrapNodeSet: out of memory\n");
774 return(NULL);
775 }
776 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
777 ret->type = XPATH_NODESET;
778 ret->nodesetval = val;
779 return(ret);
780}
781
782/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000783 * xmlXPathFreeNodeSetList:
784 * @obj: an existing NodeSetList object
785 *
786 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
787 * the list contrary to xmlXPathFreeObject().
788 */
789void
790xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
791 if (obj == NULL) return;
792#ifdef DEBUG
793 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
794#endif
795 xmlFree(obj);
796}
797
Daniel Veillardac260302000-10-04 13:33:43 +0000798#ifdef LIBXML_XPTR_ENABLED
799/**
800 * xmlXPathNewPoint:
801 * @node: the xmlNodePtr
802 * @index: the index within the node
803 *
804 * Create a new xmlXPathObjectPtr of type point
805 *
806 * Returns the newly created object.
807 */
808xmlXPathObjectPtr
809xmlXPathNewPoint(xmlNodePtr node, int index) {
810 xmlXPathObjectPtr ret;
811
812 if (node == NULL)
813 return(NULL);
814 if (index < 0)
815 return(NULL);
816
817 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
818 if (ret == NULL) {
819 fprintf(xmlXPathDebug, "xmlXPathNewPoint: out of memory\n");
820 return(NULL);
821 }
822 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
823 ret->type = XPATH_POINT;
824 ret->user = (void *) node;
825 ret->index = index;
826 return(ret);
827}
828
829/**
830 * xmlXPathNewRangePoints:
831 * @start: the starting point
832 * @end: the ending point
833 *
834 * Create a new xmlXPathObjectPtr of type range using 2 Points
835 *
836 * Returns the newly created object.
837 */
838xmlXPathObjectPtr
839xmlXPathNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
840 xmlXPathObjectPtr ret;
841
842 if (start == NULL)
843 return(NULL);
844 if (end == NULL)
845 return(NULL);
846 if (start->type != XPATH_POINT)
847 return(NULL);
848 if (end->type != XPATH_POINT)
849 return(NULL);
850
851 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
852 if (ret == NULL) {
853 fprintf(xmlXPathDebug, "xmlXPathNewRangePoints: out of memory\n");
854 return(NULL);
855 }
856 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
857 ret->type = XPATH_RANGE;
858 ret->user = start->user;
859 ret->index = start->index;
860 ret->user2 = end->user;
861 ret->index2 = end->index;
862 return(ret);
863}
864
865/**
866 * xmlXPathNewRangePointNode:
867 * @start: the starting point
868 * @end: the ending node
869 *
870 * Create a new xmlXPathObjectPtr of type range from a point to a node
871 *
872 * Returns the newly created object.
873 */
874xmlXPathObjectPtr
875xmlXPathNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
876 xmlXPathObjectPtr ret;
877
878 if (start == NULL)
879 return(NULL);
880 if (end == NULL)
881 return(NULL);
882 if (start->type != XPATH_POINT)
883 return(NULL);
884
885 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
886 if (ret == NULL) {
887 fprintf(xmlXPathDebug, "xmlXPathNewRangePointNode: out of memory\n");
888 return(NULL);
889 }
890 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
891 ret->type = XPATH_RANGE;
892 ret->user = start->user;
893 ret->index = start->index;
894 ret->user2 = end;
895 ret->index2 = -1;
896 return(ret);
897}
898
899/**
900 * xmlXPathNewRangeNodePoint:
901 * @start: the starting node
902 * @end: the ending point
903 *
904 * Create a new xmlXPathObjectPtr of type range from a node to a point
905 *
906 * Returns the newly created object.
907 */
908xmlXPathObjectPtr
909xmlXPathNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
910 xmlXPathObjectPtr ret;
911
912 if (start == NULL)
913 return(NULL);
914 if (end == NULL)
915 return(NULL);
916 if (start->type != XPATH_POINT)
917 return(NULL);
918 if (end->type != XPATH_POINT)
919 return(NULL);
920
921 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
922 if (ret == NULL) {
923 fprintf(xmlXPathDebug, "xmlXPathNewRangeNodePoint: out of memory\n");
924 return(NULL);
925 }
926 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
927 ret->type = XPATH_RANGE;
928 ret->user = start;
929 ret->index = -1;
930 ret->user2 = end->user;
931 ret->index2 = end->index;
932 return(ret);
933}
934
935/**
936 * xmlXPathNewRangeNodes:
937 * @start: the starting node
938 * @end: the ending node
939 *
940 * Create a new xmlXPathObjectPtr of type range using 2 nodes
941 *
942 * Returns the newly created object.
943 */
944xmlXPathObjectPtr
945xmlXPathNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
946 xmlXPathObjectPtr ret;
947
948 if (start == NULL)
949 return(NULL);
950 if (end == NULL)
951 return(NULL);
952
953 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
954 if (ret == NULL) {
955 fprintf(xmlXPathDebug, "xmlXPathNewRangeNodes: out of memory\n");
956 return(NULL);
957 }
958 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
959 ret->type = XPATH_RANGE;
960 ret->user = start;
961 ret->index = -1;
962 ret->user2 = end;
963 ret->index2 = -1;
964 return(ret);
965}
966
967/**
968 * xmlXPathNewRangeNodeObject:
969 * @start: the starting node
970 * @end: the ending object
971 *
972 * Create a new xmlXPathObjectPtr of type range from a not to an object
973 *
974 * Returns the newly created object.
975 */
976xmlXPathObjectPtr
977xmlXPathNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
978 xmlXPathObjectPtr ret;
979
980 if (start == NULL)
981 return(NULL);
982 if (end == NULL)
983 return(NULL);
984 switch (end->type) {
985 case XPATH_POINT:
986 break;
987 case XPATH_NODESET:
988 /*
989 * Empty set ...
990 */
991 if (end->nodesetval->nodeNr <= 0)
992 return(NULL);
993 break;
994 default:
995 TODO
996 return(NULL);
997 }
998
999 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1000 if (ret == NULL) {
1001 fprintf(xmlXPathDebug, "xmlXPathNewRangeNodeObject: out of memory\n");
1002 return(NULL);
1003 }
1004 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1005 ret->type = XPATH_RANGE;
1006 ret->user = start;
1007 ret->index = -1;
1008 switch (end->type) {
1009 case XPATH_POINT:
1010 ret->user2 = end->user;
1011 ret->index2 = end->index;
1012 case XPATH_NODESET: {
1013 ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - -1];
1014 ret->index2 = -1;
1015 break;
1016 }
1017 default:
1018 STRANGE
1019 return(NULL);
1020 }
1021 ret->user2 = end;
1022 ret->index2 = -1;
1023 return(ret);
1024}
1025
1026#define XML_RANGESET_DEFAULT 10
1027
1028/**
1029 * xmlXPathRangeSetCreate:
1030 * @val: an initial xmlXPathObjectPtr, or NULL
1031 *
1032 * Create a new xmlRangeSetPtr of type double and of value @val
1033 *
1034 * Returns the newly created object.
1035 */
1036xmlRangeSetPtr
1037xmlXPathRangeSetCreate(xmlXPathObjectPtr val) {
1038 xmlRangeSetPtr ret;
1039
1040 ret = (xmlRangeSetPtr) xmlMalloc(sizeof(xmlRangeSet));
1041 if (ret == NULL) {
1042 fprintf(xmlXPathDebug, "xmlXPathNewRangeSet: out of memory\n");
1043 return(NULL);
1044 }
1045 memset(ret, 0 , (size_t) sizeof(xmlRangeSet));
1046 if (val != NULL) {
1047 ret->rangeTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
1048 sizeof(xmlXPathObjectPtr));
1049 if (ret->rangeTab == NULL) {
1050 fprintf(xmlXPathDebug, "xmlXPathNewRangeSet: out of memory\n");
1051 return(NULL);
1052 }
1053 memset(ret->rangeTab, 0 ,
1054 XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
1055 ret->rangeMax = XML_RANGESET_DEFAULT;
1056 ret->rangeTab[ret->rangeNr++] = val;
1057 }
1058 return(ret);
1059}
1060
1061/**
1062 * xmlXPathRangeSetAdd:
1063 * @cur: the initial range set
1064 * @val: a new xmlXPathObjectPtr
1065 *
1066 * add a new xmlXPathObjectPtr ot an existing RangeSet
1067 */
1068void
1069xmlXPathRangeSetAdd(xmlRangeSetPtr cur, xmlXPathObjectPtr val) {
1070 int i;
1071
1072 if (val == NULL) return;
1073
1074 /*
1075 * check against doublons
1076 */
1077 for (i = 0;i < cur->rangeNr;i++)
1078 if (cur->rangeTab[i] == val) return;
1079
1080 /*
1081 * grow the rangeTab if needed
1082 */
1083 if (cur->rangeMax == 0) {
1084 cur->rangeTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
1085 sizeof(xmlXPathObjectPtr));
1086 if (cur->rangeTab == NULL) {
1087 fprintf(xmlXPathDebug, "xmlXPathRangeSetAdd: out of memory\n");
1088 return;
1089 }
1090 memset(cur->rangeTab, 0 ,
1091 XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
1092 cur->rangeMax = XML_RANGESET_DEFAULT;
1093 } else if (cur->rangeNr == cur->rangeMax) {
1094 xmlXPathObjectPtr *temp;
1095
1096 cur->rangeMax *= 2;
1097 temp = (xmlXPathObjectPtr *) xmlRealloc(cur->rangeTab, cur->rangeMax *
1098 sizeof(xmlXPathObjectPtr));
1099 if (temp == NULL) {
1100 fprintf(xmlXPathDebug, "xmlXPathRangeSetAdd: out of memory\n");
1101 return;
1102 }
1103 cur->rangeTab = temp;
1104 }
1105 cur->rangeTab[cur->rangeNr++] = val;
1106}
1107
1108/**
1109 * xmlXPathRangeSetMerge:
1110 * @val1: the first RangeSet
1111 * @val2: the second RangeSet
1112 *
1113 * Merges two rangesets, all ranges from @val2 are added to @val1
1114 *
1115 * Returns val1 once extended or NULL in case of error.
1116 */
1117xmlRangeSetPtr
1118xmlXPathRangeSetMerge(xmlRangeSetPtr val1, xmlRangeSetPtr val2) {
1119 int i;
1120
1121 if (val1 == NULL) return(NULL);
1122 if (val2 == NULL) return(val1);
1123
1124 /*
1125 * !!!!! this can be optimized a lot, knowing that both
1126 * val1 and val2 already have unicity of their values.
1127 */
1128
1129 for (i = 0;i < val2->rangeNr;i++)
1130 xmlXPathRangeSetAdd(val1, val2->rangeTab[i]);
1131
1132 return(val1);
1133}
1134
1135/**
1136 * xmlXPathRangeSetDel:
1137 * @cur: the initial range set
1138 * @val: an xmlXPathObjectPtr
1139 *
1140 * Removes an xmlXPathObjectPtr from an existing RangeSet
1141 */
1142void
1143xmlXPathRangeSetDel(xmlRangeSetPtr cur, xmlXPathObjectPtr val) {
1144 int i;
1145
1146 if (cur == NULL) return;
1147 if (val == NULL) return;
1148
1149 /*
1150 * check against doublons
1151 */
1152 for (i = 0;i < cur->rangeNr;i++)
1153 if (cur->rangeTab[i] == val) break;
1154
1155 if (i >= cur->rangeNr) {
1156#ifdef DEBUG
1157 fprintf(xmlXPathDebug,
1158 "xmlXPathRangeSetDel: Range %s wasn't found in RangeList\n",
1159 val->name);
1160#endif
1161 return;
1162 }
1163 cur->rangeNr--;
1164 for (;i < cur->rangeNr;i++)
1165 cur->rangeTab[i] = cur->rangeTab[i + 1];
1166 cur->rangeTab[cur->rangeNr] = NULL;
1167}
1168
1169/**
1170 * xmlXPathRangeSetRemove:
1171 * @cur: the initial range set
1172 * @val: the index to remove
1173 *
1174 * Removes an entry from an existing RangeSet list.
1175 */
1176void
1177xmlXPathRangeSetRemove(xmlRangeSetPtr cur, int val) {
1178 if (cur == NULL) return;
1179 if (val >= cur->rangeNr) return;
1180 cur->rangeNr--;
1181 for (;val < cur->rangeNr;val++)
1182 cur->rangeTab[val] = cur->rangeTab[val + 1];
1183 cur->rangeTab[cur->rangeNr] = NULL;
1184}
1185
1186/**
1187 * xmlXPathFreeRangeSet:
1188 * @obj: the xmlRangeSetPtr to free
1189 *
1190 * Free the RangeSet compound (not the actual ranges !).
1191 */
1192void
1193xmlXPathFreeRangeSet(xmlRangeSetPtr obj) {
1194 if (obj == NULL) return;
1195 if (obj->rangeTab != NULL) {
1196#ifdef DEBUG
1197 memset(obj->rangeTab, 0xB ,
1198 (size_t) sizeof(xmlXPathObjectPtr) * obj->rangeMax);
1199#endif
1200 xmlFree(obj->rangeTab);
1201 }
1202#ifdef DEBUG
1203 memset(obj, 0xB , (size_t) sizeof(xmlRangeSet));
1204#endif
1205 xmlFree(obj);
1206}
1207
1208#if defined(DEBUG) || defined(DEBUG_STEP)
1209/**
1210 * xmlXPathDebugRangeSet:
1211 * @output: a FILE * for the output
1212 * @obj: the xmlRangeSetPtr to free
1213 *
1214 * Quick display of a RangeSet
1215 */
1216void
1217xmlXPathDebugRangeSet(FILE *output, xmlRangeSetPtr obj) {
1218 int i;
1219
1220 if (output == NULL) output = xmlXPathDebug;
1221 if (obj == NULL) {
1222 fprintf(output, "RangeSet == NULL !\n");
1223 return;
1224 }
1225 if (obj->rangeNr == 0) {
1226 fprintf(output, "RangeSet is empty\n");
1227 return;
1228 }
1229 if (obj->rangeTab == NULL) {
1230 fprintf(output, " rangeTab == NULL !\n");
1231 return;
1232 }
1233 for (i = 0; i < obj->rangeNr; i++) {
1234 if (obj->rangeTab[i] == NULL) {
1235 fprintf(output, " NULL !\n");
1236 return;
1237 }
1238 if ((obj->rangeTab[i]->type == XML_DOCUMENT_NODE) ||
1239 (obj->rangeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1240 fprintf(output, " /");
1241 else if (obj->rangeTab[i]->name == NULL)
1242 fprintf(output, " noname!");
1243 else fprintf(output, " %s", obj->rangeTab[i]->name);
1244 }
1245 fprintf(output, "\n");
1246}
1247#endif
1248
1249/**
1250 * xmlXPathNewRangeSetNodes:
1251 * @start: the NodePtr value
1252 * @end: the NodePtr value
1253 *
1254 * Create a new xmlXPathObjectPtr of type RangeSet and initialize
1255 * it with the single range made of the two nodes @start and @end
1256 *
1257 * Returns the newly created object.
1258 */
1259xmlXPathObjectPtr
1260xmlXPathNewRangeSetNodes(xmlNodePtr start, xmlNodePtr end) {
1261 xmlXPathObjectPtr ret;
1262
1263 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1264 if (ret == NULL) {
1265 fprintf(xmlXPathDebug, "xmlXPathNewRangeSet: out of memory\n");
1266 return(NULL);
1267 }
1268 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1269 ret->type = XPATH_LOCATIONSET;
1270 ret->user = xmlXPathRangeSetCreate(xmlXPathNewRangeNodes(start, end));
1271 return(ret);
1272}
1273
1274/**
1275 * xmlXPathWrapRangeSet:
1276 * @val: the RangeSet value
1277 *
1278 * Wrap the RangeSet @val in a new xmlXPathObjectPtr
1279 *
1280 * Returns the newly created object.
1281 */
1282xmlXPathObjectPtr
1283xmlXPathWrapRangeSet(xmlRangeSetPtr val) {
1284 xmlXPathObjectPtr ret;
1285
1286 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1287 if (ret == NULL) {
1288 fprintf(xmlXPathDebug, "xmlXPathWrapRangeSet: out of memory\n");
1289 return(NULL);
1290 }
1291 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1292 ret->type = XPATH_LOCATIONSET;
1293 ret->user = (void *) val;
1294 return(ret);
1295}
1296
1297#endif /* LIBXML_XPTR_ENABLED */
1298
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001299/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001300 * xmlXPathFreeObject:
1301 * @obj: the object to free
1302 *
1303 * Free up an xmlXPathObjectPtr object.
1304 */
1305void
1306xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1307 if (obj == NULL) return;
Daniel Veillardac260302000-10-04 13:33:43 +00001308 if (obj->type == XPATH_NODESET) {
1309 if (obj->nodesetval != NULL)
1310 xmlXPathFreeNodeSet(obj->nodesetval);
1311 } else if (obj->type == XPATH_STRING) {
1312 if (obj->stringval != NULL)
1313 xmlFree(obj->stringval);
1314 }
1315
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001316#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001317 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001318#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001319 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001320}
1321
1322/************************************************************************
1323 * *
1324 * Routines to handle XPath contexts *
1325 * *
1326 ************************************************************************/
1327
1328/**
1329 * xmlXPathNewContext:
1330 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001331 *
1332 * Create a new xmlXPathContext
1333 *
1334 * Returns the xmlXPathContext just allocated.
1335 */
1336xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001337xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001338 xmlXPathContextPtr ret;
1339
Daniel Veillard6454aec1999-09-02 22:04:43 +00001340 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001341 if (ret == NULL) {
1342 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
1343 return(NULL);
1344 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001345 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001346 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001347 ret->node = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001348
1349 ret->nb_variables = 0;
1350 ret->max_variables = 0;
1351 ret->variables = NULL;
1352
1353 ret->nb_types = 0;
1354 ret->max_types = 0;
1355 ret->types = NULL;
1356
1357 ret->nb_funcs = 0;
1358 ret->max_funcs = 0;
1359 ret->funcs = NULL;
1360
1361 ret->nb_axis = 0;
1362 ret->max_axis = 0;
1363 ret->axis = NULL;
1364
Daniel Veillardb96e6431999-08-29 21:02:19 +00001365 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001366 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001367 ret->nsNr = 0;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001368
1369 ret->contextSize = -1;
1370 ret->proximityPosition = -1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001371 return(ret);
1372}
1373
1374/**
1375 * xmlXPathFreeContext:
1376 * @ctxt: the context to free
1377 *
1378 * Free up an xmlXPathContext
1379 */
1380void
1381xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001382 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001383 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001384
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001385#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001386 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001387#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001388 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001389}
1390
1391/************************************************************************
1392 * *
1393 * Routines to handle XPath parser contexts *
1394 * *
1395 ************************************************************************/
1396
Daniel Veillard740abf52000-10-02 23:04:54 +00001397#define CHECK_CTXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001398 if (ctxt == NULL) { \
1399 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
1400 __FILE__, __LINE__); \
1401 } \
1402
1403
Daniel Veillard740abf52000-10-02 23:04:54 +00001404#define CHECK_CONTEXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001405 if (ctxt == NULL) { \
1406 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
1407 __FILE__, __LINE__); \
1408 } \
1409 if (ctxt->doc == NULL) { \
1410 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
1411 __FILE__, __LINE__); \
1412 } \
Daniel Veillardcf461992000-03-14 18:30:20 +00001413 if (ctxt->doc->children == NULL) { \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001414 fprintf(xmlXPathDebug, \
1415 "%s:%d Internal error: document without root\n", \
1416 __FILE__, __LINE__); \
1417 } \
1418
1419
1420/**
1421 * xmlXPathNewParserContext:
1422 * @str: the XPath expression
1423 * @ctxt: the XPath context
1424 *
1425 * Create a new xmlXPathParserContext
1426 *
1427 * Returns the xmlXPathParserContext just allocated.
1428 */
1429xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001430xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001431 xmlXPathParserContextPtr ret;
1432
Daniel Veillard6454aec1999-09-02 22:04:43 +00001433 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001434 if (ret == NULL) {
1435 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
1436 return(NULL);
1437 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001438 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001439 ret->cur = ret->base = str;
1440 ret->context = ctxt;
1441
1442 /* Allocate the value stack */
1443 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001444 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001445 ret->valueNr = 0;
1446 ret->valueMax = 10;
1447 ret->value = NULL;
1448 return(ret);
1449}
1450
1451/**
1452 * xmlXPathFreeParserContext:
1453 * @ctxt: the context to free
1454 *
1455 * Free up an xmlXPathParserContext
1456 */
1457void
1458xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1459 if (ctxt->valueTab != NULL) {
1460#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001461 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001462#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001463 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001464 }
1465#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001466 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001467#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001468 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001469}
1470
1471/************************************************************************
1472 * *
1473 * The implicit core function library *
1474 * *
1475 ************************************************************************/
1476
1477/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001478 * Auto-pop and cast to a number
1479 */
1480void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1481
1482#define CHECK_ARITY(x) \
1483 if (nargs != (x)) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001484 XP_ERROR(XPATH_INVALID_ARITY); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001485 } \
1486
1487
1488#define POP_FLOAT \
1489 arg = valuePop(ctxt); \
1490 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001491 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001492 } \
1493 if (arg->type != XPATH_NUMBER) { \
1494 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001495 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001496 arg = valuePop(ctxt); \
1497 }
1498
1499/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001500 * xmlXPathEqualNodeSetString
1501 * @arg: the nodeset object argument
1502 * @str: the string to compare to.
1503 *
1504 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1505 * If one object to be compared is a node-set and the other is a string,
1506 * then the comparison will be true if and only if there is a node in
1507 * the node-set such that the result of performing the comparison on the
1508 * string-value of the node and the other string is true.
1509 *
1510 * Returns 0 or 1 depending on the results of the test.
1511 */
1512int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001513xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001514 int i;
1515 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001516 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001517
1518 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
1519 return(0);
1520 ns = arg->nodesetval;
1521 for (i = 0;i < ns->nodeNr;i++) {
1522 str2 = xmlNodeGetContent(ns->nodeTab[i]);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001523 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001524 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001525 return(1);
1526 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001527 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001528 }
1529 return(0);
1530}
1531
1532/**
1533 * xmlXPathEqualNodeSetFloat
1534 * @arg: the nodeset object argument
1535 * @f: the float to compare to
1536 *
1537 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1538 * If one object to be compared is a node-set and the other is a number,
1539 * then the comparison will be true if and only if there is a node in
1540 * the node-set such that the result of performing the comparison on the
1541 * number to be compared and on the result of converting the string-value
1542 * of that node to a number using the number function is true.
1543 *
1544 * Returns 0 or 1 depending on the results of the test.
1545 */
1546int
1547xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001548 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001549
1550 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1551 return(0);
1552
1553 if (isnan(f))
1554 sprintf(buf, "NaN");
1555 else if (isinf(f) > 0)
1556 sprintf(buf, "+Infinity");
1557 else if (isinf(f) < 0)
1558 sprintf(buf, "-Infinity");
1559 else
1560 sprintf(buf, "%0g", f);
1561
Daniel Veillardb96e6431999-08-29 21:02:19 +00001562 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001563}
1564
1565
1566/**
1567 * xmlXPathEqualNodeSets
1568 * @arg1: first nodeset object argument
1569 * @arg2: second nodeset object argument
1570 *
1571 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1572 * If both objects to be compared are node-sets, then the comparison
1573 * will be true if and only if there is a node in the first node-set and
1574 * a node in the second node-set such that the result of performing the
1575 * comparison on the string-values of the two nodes is true.
1576 *
1577 * (needless to say, this is a costly operation)
1578 *
1579 * Returns 0 or 1 depending on the results of the test.
1580 */
1581int
1582xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1583 int i;
1584 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001585 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001586
1587 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1588 return(0);
1589 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1590 return(0);
1591
1592 ns = arg1->nodesetval;
1593 for (i = 0;i < ns->nodeNr;i++) {
1594 str = xmlNodeGetContent(ns->nodeTab[i]);
1595 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001596 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001597 return(1);
1598 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001599 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001600 }
1601 return(0);
1602}
1603
1604/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001605 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001606 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001607 *
1608 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1609 *
1610 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001611 */
1612int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001613xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1614 xmlXPathObjectPtr arg1, arg2;
1615 int ret = 0;
1616
1617 arg1 = valuePop(ctxt);
1618 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001619 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001620
1621 arg2 = valuePop(ctxt);
1622 if (arg2 == NULL) {
1623 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001624 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001625 }
1626
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001627 if (arg1 == arg2) {
1628#ifdef DEBUG_EXPR
1629 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1630#endif
1631 return(1);
1632 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001633
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001634 switch (arg1->type) {
1635 case XPATH_UNDEFINED:
1636#ifdef DEBUG_EXPR
1637 fprintf(xmlXPathDebug, "Equal: undefined\n");
1638#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001639 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001640 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001641 switch (arg2->type) {
1642 case XPATH_UNDEFINED:
1643#ifdef DEBUG_EXPR
1644 fprintf(xmlXPathDebug, "Equal: undefined\n");
1645#endif
1646 break;
1647 case XPATH_NODESET:
1648 ret = xmlXPathEqualNodeSets(arg1, arg2);
1649 break;
1650 case XPATH_BOOLEAN:
1651 if ((arg1->nodesetval == NULL) ||
1652 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1653 else
1654 ret = 1;
1655 ret = (ret == arg2->boolval);
1656 break;
1657 case XPATH_NUMBER:
1658 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1659 break;
1660 case XPATH_STRING:
1661 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1662 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001663 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001664 case XPATH_POINT:
1665 case XPATH_RANGE:
1666 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001667 TODO
1668 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001669 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001670 break;
1671 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001672 switch (arg2->type) {
1673 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001674#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001675 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001676#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001677 break;
1678 case XPATH_NODESET:
1679 if ((arg2->nodesetval == NULL) ||
1680 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1681 else
1682 ret = 1;
1683 break;
1684 case XPATH_BOOLEAN:
1685#ifdef DEBUG_EXPR
1686 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1687 arg1->boolval, arg2->boolval);
1688#endif
1689 ret = (arg1->boolval == arg2->boolval);
1690 break;
1691 case XPATH_NUMBER:
1692 if (arg2->floatval) ret = 1;
1693 else ret = 0;
1694 ret = (arg1->boolval == ret);
1695 break;
1696 case XPATH_STRING:
1697 if ((arg2->stringval == NULL) ||
1698 (arg2->stringval[0] == 0)) ret = 0;
1699 else
1700 ret = 1;
1701 ret = (arg1->boolval == ret);
1702 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001703 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001704 case XPATH_POINT:
1705 case XPATH_RANGE:
1706 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001707 TODO
1708 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001709 }
1710 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001711 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001712 switch (arg2->type) {
1713 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001714#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001715 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001716#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001717 break;
1718 case XPATH_NODESET:
1719 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1720 break;
1721 case XPATH_BOOLEAN:
1722 if (arg1->floatval) ret = 1;
1723 else ret = 0;
1724 ret = (arg2->boolval == ret);
1725 break;
1726 case XPATH_STRING:
1727 valuePush(ctxt, arg2);
1728 xmlXPathNumberFunction(ctxt, 1);
1729 arg2 = valuePop(ctxt);
1730 /* no break on purpose */
1731 case XPATH_NUMBER:
1732 ret = (arg1->floatval == arg2->floatval);
1733 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001734 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001735 case XPATH_POINT:
1736 case XPATH_RANGE:
1737 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001738 TODO
1739 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001740 }
1741 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001742 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001743 switch (arg2->type) {
1744 case XPATH_UNDEFINED:
1745#ifdef DEBUG_EXPR
1746 fprintf(xmlXPathDebug, "Equal: undefined\n");
1747#endif
1748 break;
1749 case XPATH_NODESET:
1750 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1751 break;
1752 case XPATH_BOOLEAN:
1753 if ((arg1->stringval == NULL) ||
1754 (arg1->stringval[0] == 0)) ret = 0;
1755 else
1756 ret = 1;
1757 ret = (arg2->boolval == ret);
1758 break;
1759 case XPATH_STRING:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001760 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001761 break;
1762 case XPATH_NUMBER:
1763 valuePush(ctxt, arg1);
1764 xmlXPathNumberFunction(ctxt, 1);
1765 arg1 = valuePop(ctxt);
1766 ret = (arg1->floatval == arg2->floatval);
1767 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001768 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001769 case XPATH_POINT:
1770 case XPATH_RANGE:
1771 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001772 TODO
1773 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001774 }
1775 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001776 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001777 case XPATH_POINT:
1778 case XPATH_RANGE:
1779 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001780 TODO
1781 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001782 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001783 xmlXPathFreeObject(arg1);
1784 xmlXPathFreeObject(arg2);
1785 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001786}
1787
1788/**
1789 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001790 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001791 * @inf: less than (1) or greater than (2)
1792 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001793 *
1794 * Implement the compare operation on XPath objects:
1795 * @arg1 < @arg2 (1, 1, ...
1796 * @arg1 <= @arg2 (1, 0, ...
1797 * @arg1 > @arg2 (0, 1, ...
1798 * @arg1 >= @arg2 (0, 0, ...
1799 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001800 * When neither object to be compared is a node-set and the operator is
1801 * <=, <, >=, >, then the objects are compared by converted both objects
1802 * to numbers and comparing the numbers according to IEEE 754. The <
1803 * comparison will be true if and only if the first number is less than the
1804 * second number. The <= comparison will be true if and only if the first
1805 * number is less than or equal to the second number. The > comparison
1806 * will be true if and only if the first number is greater than the second
1807 * number. The >= comparison will be true if and only if the first number
1808 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001809 */
1810int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001811xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1812 int ret = 0;
1813 xmlXPathObjectPtr arg1, arg2;
1814
1815 arg2 = valuePop(ctxt);
1816 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1817 if (arg2 != NULL)
1818 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001819 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001820 }
1821
1822 arg1 = valuePop(ctxt);
1823 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1824 if (arg1 != NULL)
1825 xmlXPathFreeObject(arg1);
1826 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001827 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001828 }
1829
1830 if (arg1->type != XPATH_NUMBER) {
1831 valuePush(ctxt, arg1);
1832 xmlXPathNumberFunction(ctxt, 1);
1833 arg1 = valuePop(ctxt);
1834 }
1835 if (arg1->type != XPATH_NUMBER) {
1836 xmlXPathFreeObject(arg1);
1837 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001838 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001839 }
1840 if (arg2->type != XPATH_NUMBER) {
1841 valuePush(ctxt, arg2);
1842 xmlXPathNumberFunction(ctxt, 1);
1843 arg2 = valuePop(ctxt);
1844 }
1845 if (arg2->type != XPATH_NUMBER) {
1846 xmlXPathFreeObject(arg1);
1847 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001848 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001849 }
1850 /*
1851 * Add tests for infinity and nan
1852 * => feedback on 3.4 for Inf and NaN
1853 */
1854 if (inf && strict)
1855 ret = (arg1->floatval < arg2->floatval);
1856 else if (inf && !strict)
1857 ret = (arg1->floatval <= arg2->floatval);
1858 else if (!inf && strict)
1859 ret = (arg1->floatval > arg2->floatval);
1860 else if (!inf && !strict)
1861 ret = (arg1->floatval >= arg2->floatval);
1862 xmlXPathFreeObject(arg1);
1863 xmlXPathFreeObject(arg2);
1864 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001865}
1866
1867/**
1868 * xmlXPathValueFlipSign:
1869 * @ctxt: the XPath Parser context
1870 *
1871 * Implement the unary - operation on an XPath object
1872 * The numeric operators convert their operands to numbers as if
1873 * by calling the number function.
1874 */
1875void
1876xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1877 xmlXPathObjectPtr arg;
1878
1879 POP_FLOAT
1880 arg->floatval = -arg->floatval;
1881 valuePush(ctxt, arg);
1882}
1883
1884/**
1885 * xmlXPathAddValues:
1886 * @ctxt: the XPath Parser context
1887 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001888 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001889 * The numeric operators convert their operands to numbers as if
1890 * by calling the number function.
1891 */
1892void
1893xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1894 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001895 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001896
1897 POP_FLOAT
1898 val = arg->floatval;
1899 xmlXPathFreeObject(arg);
1900
1901 POP_FLOAT
1902 arg->floatval += val;
1903 valuePush(ctxt, arg);
1904}
1905
1906/**
1907 * xmlXPathSubValues:
1908 * @ctxt: the XPath Parser context
1909 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001910 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001911 * The numeric operators convert their operands to numbers as if
1912 * by calling the number function.
1913 */
1914void
1915xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1916 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001917 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001918
1919 POP_FLOAT
1920 val = arg->floatval;
1921 xmlXPathFreeObject(arg);
1922
1923 POP_FLOAT
1924 arg->floatval -= val;
1925 valuePush(ctxt, arg);
1926}
1927
1928/**
1929 * xmlXPathMultValues:
1930 * @ctxt: the XPath Parser context
1931 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001932 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001933 * The numeric operators convert their operands to numbers as if
1934 * by calling the number function.
1935 */
1936void
1937xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1938 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001939 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001940
1941 POP_FLOAT
1942 val = arg->floatval;
1943 xmlXPathFreeObject(arg);
1944
1945 POP_FLOAT
1946 arg->floatval *= val;
1947 valuePush(ctxt, arg);
1948}
1949
1950/**
1951 * xmlXPathDivValues:
1952 * @ctxt: the XPath Parser context
1953 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001954 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001955 * The numeric operators convert their operands to numbers as if
1956 * by calling the number function.
1957 */
1958void
1959xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1960 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001961 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001962
1963 POP_FLOAT
1964 val = arg->floatval;
1965 xmlXPathFreeObject(arg);
1966
1967 POP_FLOAT
1968 arg->floatval /= val;
1969 valuePush(ctxt, arg);
1970}
1971
1972/**
1973 * xmlXPathModValues:
1974 * @ctxt: the XPath Parser context
1975 *
1976 * Implement the div operation on XPath objects: @arg1 / @arg2
1977 * The numeric operators convert their operands to numbers as if
1978 * by calling the number function.
1979 */
1980void
1981xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1982 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001983 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001984
1985 POP_FLOAT
1986 val = arg->floatval;
1987 xmlXPathFreeObject(arg);
1988
1989 POP_FLOAT
1990 arg->floatval /= val;
1991 valuePush(ctxt, arg);
1992}
1993
1994/************************************************************************
1995 * *
1996 * The traversal functions *
1997 * *
1998 ************************************************************************/
1999
Daniel Veillard740abf52000-10-02 23:04:54 +00002000typedef enum {
2001 AXIS_ANCESTOR = 1,
2002 AXIS_ANCESTOR_OR_SELF,
2003 AXIS_ATTRIBUTE,
2004 AXIS_CHILD,
2005 AXIS_DESCENDANT,
2006 AXIS_DESCENDANT_OR_SELF,
2007 AXIS_FOLLOWING,
2008 AXIS_FOLLOWING_SIBLING,
2009 AXIS_NAMESPACE,
2010 AXIS_PARENT,
2011 AXIS_PRECEDING,
2012 AXIS_PRECEDING_SIBLING,
2013 AXIS_SELF
2014} xmlXPathAxisVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002015
2016/*
2017 * A traversal function enumerates nodes along an axis.
2018 * Initially it must be called with NULL, and it indicates
2019 * termination on the axis by returning NULL.
2020 */
2021typedef xmlNodePtr (*xmlXPathTraversalFunction)
2022 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
2023
2024/**
2025 * mlXPathNextSelf:
2026 * @ctxt: the XPath Parser context
2027 * @cur: the current node in the traversal
2028 *
2029 * Traversal function for the "self" direction
2030 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00002031 *
2032 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002033 */
2034xmlNodePtr
2035xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2036 if (cur == NULL)
2037 return(ctxt->context->node);
2038 return(NULL);
2039}
2040
2041/**
2042 * mlXPathNextChild:
2043 * @ctxt: the XPath Parser context
2044 * @cur: the current node in the traversal
2045 *
2046 * Traversal function for the "child" direction
2047 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002048 *
2049 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002050 */
2051xmlNodePtr
2052xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002053 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002054 if (ctxt->context->node == NULL) return(NULL);
2055 switch (ctxt->context->node->type) {
2056 case XML_ELEMENT_NODE:
2057 case XML_TEXT_NODE:
2058 case XML_CDATA_SECTION_NODE:
2059 case XML_ENTITY_REF_NODE:
2060 case XML_ENTITY_NODE:
2061 case XML_PI_NODE:
2062 case XML_COMMENT_NODE:
2063 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002064 case XML_DTD_NODE:
2065 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002066 case XML_DOCUMENT_NODE:
2067 case XML_DOCUMENT_TYPE_NODE:
2068 case XML_DOCUMENT_FRAG_NODE:
2069 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002070#ifdef LIBXML_SGML_ENABLED
2071 case XML_SGML_DOCUMENT_NODE:
2072#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002073 return(((xmlDocPtr) ctxt->context->node)->children);
2074 case XML_ELEMENT_DECL:
2075 case XML_ATTRIBUTE_DECL:
2076 case XML_ENTITY_DECL:
2077 case XML_ATTRIBUTE_NODE:
2078 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002079 }
2080 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002081 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002082 if ((cur->type == XML_DOCUMENT_NODE) ||
2083 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002084 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002085 return(cur->next);
2086}
2087
2088/**
2089 * mlXPathNextDescendant:
2090 * @ctxt: the XPath Parser context
2091 * @cur: the current node in the traversal
2092 *
2093 * Traversal function for the "descendant" direction
2094 * the descendant axis contains the descendants of the context node in document
2095 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002096 *
2097 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002098 */
2099xmlNodePtr
2100xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002101 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002102 if (ctxt->context->node == NULL)
2103 return(NULL);
2104 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
2105 return(NULL);
2106
Daniel Veillardb05deb71999-08-10 19:04:08 +00002107 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00002108 return(ctxt->context->doc->children);
2109 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002110 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002111
Daniel Veillardbe803962000-06-28 23:40:59 +00002112 if (cur->children != NULL)
2113 {
2114 if (cur->children->type != XML_ENTITY_DECL)
2115 return(cur->children);
2116 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002117 if (cur->next != NULL) return(cur->next);
2118
2119 do {
2120 cur = cur->parent;
2121 if (cur == NULL) return(NULL);
2122 if (cur == ctxt->context->node) return(NULL);
2123 if (cur->next != NULL) {
2124 cur = cur->next;
2125 return(cur);
2126 }
2127 } while (cur != NULL);
2128 return(cur);
2129}
2130
2131/**
2132 * mlXPathNextDescendantOrSelf:
2133 * @ctxt: the XPath Parser context
2134 * @cur: the current node in the traversal
2135 *
2136 * Traversal function for the "descendant-or-self" direction
2137 * the descendant-or-self axis contains the context node and the descendants
2138 * of the context node in document order; thus the context node is the first
2139 * node on the axis, and the first child of the context node is the second node
2140 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002141 *
2142 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002143 */
2144xmlNodePtr
2145xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002146 if (cur == NULL) {
2147 if (ctxt->context->node == NULL)
2148 return(NULL);
2149 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
2150 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002151 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002152 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002153
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002154 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002155}
2156
2157/**
2158 * xmlXPathNextParent:
2159 * @ctxt: the XPath Parser context
2160 * @cur: the current node in the traversal
2161 *
2162 * Traversal function for the "parent" direction
2163 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002164 *
2165 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002166 */
2167xmlNodePtr
2168xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2169 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002170 * the parent of an attribute or namespace node is the element
2171 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002172 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002173 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002174 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002175 if (ctxt->context->node == NULL) return(NULL);
2176 switch (ctxt->context->node->type) {
2177 case XML_ELEMENT_NODE:
2178 case XML_TEXT_NODE:
2179 case XML_CDATA_SECTION_NODE:
2180 case XML_ENTITY_REF_NODE:
2181 case XML_ENTITY_NODE:
2182 case XML_PI_NODE:
2183 case XML_COMMENT_NODE:
2184 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002185 case XML_DTD_NODE:
2186 case XML_ELEMENT_DECL:
2187 case XML_ATTRIBUTE_DECL:
2188 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002189 if (ctxt->context->node->parent == NULL)
2190 return((xmlNodePtr) ctxt->context->doc);
2191 return(ctxt->context->node->parent);
2192 case XML_ATTRIBUTE_NODE: {
2193 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2194
Daniel Veillardcf461992000-03-14 18:30:20 +00002195 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002196 }
2197 case XML_DOCUMENT_NODE:
2198 case XML_DOCUMENT_TYPE_NODE:
2199 case XML_DOCUMENT_FRAG_NODE:
2200 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002201#ifdef LIBXML_SGML_ENABLED
2202 case XML_SGML_DOCUMENT_NODE:
2203#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002204 return(NULL);
2205 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002206 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002207 return(NULL);
2208}
2209
2210/**
2211 * xmlXPathNextAncestor:
2212 * @ctxt: the XPath Parser context
2213 * @cur: the current node in the traversal
2214 *
2215 * Traversal function for the "ancestor" direction
2216 * the ancestor axis contains the ancestors of the context node; the ancestors
2217 * of the context node consist of the parent of context node and the parent's
2218 * parent and so on; the nodes are ordered in reverse document order; thus the
2219 * parent is the first node on the axis, and the parent's parent is the second
2220 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002221 *
2222 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002223 */
2224xmlNodePtr
2225xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2226 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002227 * the parent of an attribute or namespace node is the element
2228 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002229 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002230 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002231 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002232 if (ctxt->context->node == NULL) return(NULL);
2233 switch (ctxt->context->node->type) {
2234 case XML_ELEMENT_NODE:
2235 case XML_TEXT_NODE:
2236 case XML_CDATA_SECTION_NODE:
2237 case XML_ENTITY_REF_NODE:
2238 case XML_ENTITY_NODE:
2239 case XML_PI_NODE:
2240 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002241 case XML_DTD_NODE:
2242 case XML_ELEMENT_DECL:
2243 case XML_ATTRIBUTE_DECL:
2244 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002245 case XML_NOTATION_NODE:
2246 if (ctxt->context->node->parent == NULL)
2247 return((xmlNodePtr) ctxt->context->doc);
2248 return(ctxt->context->node->parent);
2249 case XML_ATTRIBUTE_NODE: {
2250 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2251
Daniel Veillardcf461992000-03-14 18:30:20 +00002252 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002253 }
2254 case XML_DOCUMENT_NODE:
2255 case XML_DOCUMENT_TYPE_NODE:
2256 case XML_DOCUMENT_FRAG_NODE:
2257 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002258#ifdef LIBXML_SGML_ENABLED
2259 case XML_SGML_DOCUMENT_NODE:
2260#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002261 return(NULL);
2262 }
2263 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002264 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002265 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002266 return((xmlNodePtr) ctxt->context->doc);
2267 if (cur == (xmlNodePtr) ctxt->context->doc)
2268 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002269 switch (cur->type) {
2270 case XML_ELEMENT_NODE:
2271 case XML_TEXT_NODE:
2272 case XML_CDATA_SECTION_NODE:
2273 case XML_ENTITY_REF_NODE:
2274 case XML_ENTITY_NODE:
2275 case XML_PI_NODE:
2276 case XML_COMMENT_NODE:
2277 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002278 case XML_DTD_NODE:
2279 case XML_ELEMENT_DECL:
2280 case XML_ATTRIBUTE_DECL:
2281 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002282 return(cur->parent);
2283 case XML_ATTRIBUTE_NODE: {
2284 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2285
Daniel Veillardcf461992000-03-14 18:30:20 +00002286 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002287 }
2288 case XML_DOCUMENT_NODE:
2289 case XML_DOCUMENT_TYPE_NODE:
2290 case XML_DOCUMENT_FRAG_NODE:
2291 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002292#ifdef LIBXML_SGML_ENABLED
2293 case XML_SGML_DOCUMENT_NODE:
2294#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002295 return(NULL);
2296 }
2297 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002298}
2299
2300/**
2301 * xmlXPathNextAncestorOrSelf:
2302 * @ctxt: the XPath Parser context
2303 * @cur: the current node in the traversal
2304 *
2305 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00002306 * he ancestor-or-self axis contains the context node and ancestors of
2307 * the context node in reverse document order; thus the context node is
2308 * the first node on the axis, and the context node's parent the second;
2309 * parent here is defined the same as with the parent axis.
2310 *
2311 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002312 */
2313xmlNodePtr
2314xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002315 if (cur == NULL)
2316 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002317 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002318}
2319
2320/**
2321 * xmlXPathNextFollowingSibling:
2322 * @ctxt: the XPath Parser context
2323 * @cur: the current node in the traversal
2324 *
2325 * Traversal function for the "following-sibling" direction
2326 * The following-sibling axis contains the following siblings of the context
2327 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002328 *
2329 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002330 */
2331xmlNodePtr
2332xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002333 if (cur == (xmlNodePtr) ctxt->context->doc)
2334 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002335 if (cur == NULL)
2336 return(ctxt->context->node->next);
2337 return(cur->next);
2338}
2339
2340/**
2341 * xmlXPathNextPrecedingSibling:
2342 * @ctxt: the XPath Parser context
2343 * @cur: the current node in the traversal
2344 *
2345 * Traversal function for the "preceding-sibling" direction
2346 * The preceding-sibling axis contains the preceding siblings of the context
2347 * node in reverse document order; the first preceding sibling is first on the
2348 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002349 *
2350 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002351 */
2352xmlNodePtr
2353xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002354 if (cur == (xmlNodePtr) ctxt->context->doc)
2355 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002356 if (cur == NULL)
2357 return(ctxt->context->node->prev);
2358 return(cur->prev);
2359}
2360
2361/**
2362 * xmlXPathNextFollowing:
2363 * @ctxt: the XPath Parser context
2364 * @cur: the current node in the traversal
2365 *
2366 * Traversal function for the "following" direction
2367 * The following axis contains all nodes in the same document as the context
2368 * node that are after the context node in document order, excluding any
2369 * descendants and excluding attribute nodes and namespace nodes; the nodes
2370 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00002371 *
2372 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002373 */
2374xmlNodePtr
2375xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002376 if (cur != NULL && cur->children != NULL)
2377 return cur->children ;
Daniel Veillardac260302000-10-04 13:33:43 +00002378 if (cur == NULL) cur = ctxt->context->node;
2379 if (cur == NULL) return(NULL) ; /* ERROR */
2380 if (cur->next != NULL) return(cur->next) ;
Daniel Veillard740abf52000-10-02 23:04:54 +00002381 do {
2382 cur = cur->parent;
2383 if (cur == NULL) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002384 if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */
2385 if (cur->next != NULL) return(cur->next);
Daniel Veillard740abf52000-10-02 23:04:54 +00002386 } while (cur != NULL);
2387 return(cur);
2388}
2389
2390/*
Daniel Veillardac260302000-10-04 13:33:43 +00002391 * xmlXPathIsAncestor:
2392 * @ancestor: the ancestor node
2393 * @node: the current node
2394 *
2395 * Check that @ancestor is a @node's ancestor
2396 *
Daniel Veillard740abf52000-10-02 23:04:54 +00002397 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2398 */
2399static int
Daniel Veillardac260302000-10-04 13:33:43 +00002400xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002401 xmlNodePtr tmp ;
2402 if (ancestor == NULL || node == NULL) return 0 ;
2403 for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) {
2404 if (tmp->parent == ancestor)
2405 return 1 ;
2406 }
2407 return 0 ;
2408}
2409
2410/**
2411 * xmlXPathNextPreceding:
2412 * @ctxt: the XPath Parser context
2413 * @cur: the current node in the traversal
2414 *
2415 * Traversal function for the "preceding" direction
2416 * the preceding axis contains all nodes in the same document as the context
2417 * node that are before the context node in document order, excluding any
2418 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2419 * ordered in reverse document order
2420 *
2421 * Returns the next element following that axis
2422 */
2423xmlNodePtr
2424xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2425 if (cur == NULL)
2426 cur = ctxt->context->node ;
2427 do {
2428 if (cur->prev != NULL) {
2429 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2430 ;
2431 return(cur) ;
2432 }
2433
2434 cur = cur->parent;
2435 if (cur == NULL) return(NULL);
2436 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002437 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillard740abf52000-10-02 23:04:54 +00002438 return(cur);
2439}
2440
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002441/**
2442 * xmlXPathNextNamespace:
2443 * @ctxt: the XPath Parser context
2444 * @cur: the current attribute in the traversal
2445 *
2446 * Traversal function for the "namespace" direction
2447 * the namespace axis contains the namespace nodes of the context node;
2448 * the order of nodes on this axis is implementation-defined; the axis will
2449 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00002450 *
2451 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002452 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00002453xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002454xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002455 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2456 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002457 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002458 ctxt->context->namespaces =
2459 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2460 if (ctxt->context->namespaces == NULL) return(NULL);
2461 ctxt->context->nsNr = 0;
2462 }
2463 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002464}
2465
2466/**
2467 * xmlXPathNextAttribute:
2468 * @ctxt: the XPath Parser context
2469 * @cur: the current attribute in the traversal
2470 *
2471 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00002472 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00002473 *
2474 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002475 */
2476xmlAttrPtr
2477xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00002478 if (cur == NULL) {
2479 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2480 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002481 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002482 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002483 return(cur->next);
2484}
2485
2486/************************************************************************
2487 * *
2488 * NodeTest Functions *
2489 * *
2490 ************************************************************************/
2491
Daniel Veillard740abf52000-10-02 23:04:54 +00002492typedef enum {
2493 NODE_TEST_NONE = 0,
2494 NODE_TEST_TYPE = 1,
2495 NODE_TEST_PI = 2,
2496 NODE_TEST_ALL = 3,
2497 NODE_TEST_NS = 4,
2498 NODE_TEST_NAME = 5
2499} xmlXPathTestVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002500
Daniel Veillard740abf52000-10-02 23:04:54 +00002501typedef enum {
2502 NODE_TYPE_COMMENT = 50,
2503 NODE_TYPE_TEXT = 51,
2504 NODE_TYPE_PI = 52,
2505 NODE_TYPE_NODE = 53
2506} xmlXPathTypeVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002507
2508#define IS_FUNCTION 200
2509
2510/**
2511 * xmlXPathNodeCollectAndTest:
2512 * @ctxt: the XPath Parser context
Daniel Veillard740abf52000-10-02 23:04:54 +00002513 * @axis: the XPath axis
2514 * @test: the XPath test
2515 * @type: the XPath type
2516 * @prefix: the namesapce prefix if any
2517 * @name: the name used in the search if any
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002518 *
2519 * This is the function implementing a step: based on the current list
2520 * of nodes, it builds up a new list, looking at all nodes under that
2521 * axis and selecting them.
2522 *
2523 * Returns the new NodeSet resulting from the search.
2524 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002525void
2526xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2527 xmlXPathTestVal test, xmlXPathTypeVal type,
2528 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002529#ifdef DEBUG_STEP
2530 int n = 0, t = 0;
2531#endif
2532 int i;
2533 xmlNodeSetPtr ret;
2534 xmlXPathTraversalFunction next = NULL;
2535 xmlNodePtr cur = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00002536 xmlXPathObjectPtr obj;
2537 xmlNodeSetPtr nodelist;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002538
Daniel Veillard740abf52000-10-02 23:04:54 +00002539 CHECK_TYPE(XPATH_NODESET);
2540 obj = valuePop(ctxt);
2541
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002542#ifdef DEBUG_STEP
2543 fprintf(xmlXPathDebug, "new step : ");
2544#endif
2545 switch (axis) {
2546 case AXIS_ANCESTOR:
2547#ifdef DEBUG_STEP
2548 fprintf(xmlXPathDebug, "axis 'ancestors' ");
2549#endif
2550 next = xmlXPathNextAncestor; break;
2551 case AXIS_ANCESTOR_OR_SELF:
2552#ifdef DEBUG_STEP
2553 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
2554#endif
2555 next = xmlXPathNextAncestorOrSelf; break;
2556 case AXIS_ATTRIBUTE:
2557#ifdef DEBUG_STEP
2558 fprintf(xmlXPathDebug, "axis 'attributes' ");
2559#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002560 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002561 break;
2562 case AXIS_CHILD:
2563#ifdef DEBUG_STEP
2564 fprintf(xmlXPathDebug, "axis 'child' ");
2565#endif
2566 next = xmlXPathNextChild; break;
2567 case AXIS_DESCENDANT:
2568#ifdef DEBUG_STEP
2569 fprintf(xmlXPathDebug, "axis 'descendant' ");
2570#endif
2571 next = xmlXPathNextDescendant; break;
2572 case AXIS_DESCENDANT_OR_SELF:
2573#ifdef DEBUG_STEP
2574 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
2575#endif
2576 next = xmlXPathNextDescendantOrSelf; break;
2577 case AXIS_FOLLOWING:
2578#ifdef DEBUG_STEP
2579 fprintf(xmlXPathDebug, "axis 'following' ");
2580#endif
2581 next = xmlXPathNextFollowing; break;
2582 case AXIS_FOLLOWING_SIBLING:
2583#ifdef DEBUG_STEP
2584 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
2585#endif
2586 next = xmlXPathNextFollowingSibling; break;
2587 case AXIS_NAMESPACE:
2588#ifdef DEBUG_STEP
2589 fprintf(xmlXPathDebug, "axis 'namespace' ");
2590#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002591 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002592 break;
2593 case AXIS_PARENT:
2594#ifdef DEBUG_STEP
2595 fprintf(xmlXPathDebug, "axis 'parent' ");
2596#endif
2597 next = xmlXPathNextParent; break;
2598 case AXIS_PRECEDING:
2599#ifdef DEBUG_STEP
2600 fprintf(xmlXPathDebug, "axis 'preceding' ");
2601#endif
2602 next = xmlXPathNextPreceding; break;
2603 case AXIS_PRECEDING_SIBLING:
2604#ifdef DEBUG_STEP
2605 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
2606#endif
2607 next = xmlXPathNextPrecedingSibling; break;
2608 case AXIS_SELF:
2609#ifdef DEBUG_STEP
2610 fprintf(xmlXPathDebug, "axis 'self' ");
2611#endif
2612 next = xmlXPathNextSelf; break;
2613 }
Daniel Veillard740abf52000-10-02 23:04:54 +00002614 if (next == NULL)
2615 return;
2616
2617 nodelist = obj->nodesetval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002618 ret = xmlXPathNodeSetCreate(NULL);
2619#ifdef DEBUG_STEP
2620 fprintf(xmlXPathDebug, " context contains %d nodes\n",
Daniel Veillard740abf52000-10-02 23:04:54 +00002621 nodelist->nodeNr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002622 switch (test) {
2623 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002624 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002625 break;
2626 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002627 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002628 break;
2629 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002630 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002631 break;
2632 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002633 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002634 break;
2635 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002636 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002637 prefix);
2638 break;
2639 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002640 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002641 if (prefix != NULL)
2642 fprintf(xmlXPathDebug, " with namespace %s\n",
2643 prefix);
2644 break;
2645 }
2646 fprintf(xmlXPathDebug, "Testing : ");
2647#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00002648 for (i = 0;i < nodelist->nodeNr; i++) {
2649 ctxt->context->node = nodelist->nodeTab[i];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002650
2651 cur = NULL;
2652 do {
2653 cur = next(ctxt, cur);
2654 if (cur == NULL) break;
2655#ifdef DEBUG_STEP
2656 t++;
2657 fprintf(xmlXPathDebug, " %s", cur->name);
2658#endif
2659 switch (test) {
2660 case NODE_TEST_NONE:
2661 STRANGE
Daniel Veillard740abf52000-10-02 23:04:54 +00002662 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002663 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002664 if ((cur->type == type) ||
2665 ((type == XML_ELEMENT_NODE) &&
2666 ((cur->type == XML_DOCUMENT_NODE) ||
2667 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002668#ifdef DEBUG_STEP
2669 n++;
2670#endif
2671 xmlXPathNodeSetAdd(ret, cur);
2672 }
2673 break;
2674 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002675 if (cur->type == XML_PI_NODE) {
2676 if ((name != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002677 (!xmlStrEqual(name, cur->name)))
Daniel Veillardb96e6431999-08-29 21:02:19 +00002678 break;
2679#ifdef DEBUG_STEP
2680 n++;
2681#endif
2682 xmlXPathNodeSetAdd(ret, cur);
2683 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002684 break;
2685 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002686 if ((cur->type == XML_ELEMENT_NODE) ||
2687 (cur->type == XML_ATTRIBUTE_NODE)) {
2688 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002689#ifdef DEBUG_STEP
2690 n++;
2691#endif
2692 xmlXPathNodeSetAdd(ret, cur);
2693 }
2694 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002695 case NODE_TEST_NS: {
2696 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002697 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002698 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002699 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002700 switch (cur->type) {
2701 case XML_ELEMENT_NODE:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002702 if (xmlStrEqual(name, cur->name) &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002703 (((prefix == NULL) ||
2704 ((cur->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002705 (xmlStrEqual(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002706#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002707 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002708#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002709 xmlXPathNodeSetAdd(ret, cur);
2710 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002711 break;
2712 case XML_ATTRIBUTE_NODE: {
2713 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002714 if (xmlStrEqual(name, attr->name)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002715#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002716 n++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002717#endif
2718 xmlXPathNodeSetAdd(ret, cur);
2719 }
2720 break;
2721 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002722 default:
2723 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002724 }
2725 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002726 }
2727 } while (cur != NULL);
2728 }
2729#ifdef DEBUG_STEP
2730 fprintf(xmlXPathDebug,
2731 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2732#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00002733 xmlXPathFreeObject(obj);
2734 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002735}
2736
2737
2738/************************************************************************
2739 * *
2740 * Implicit tree core function library *
2741 * *
2742 ************************************************************************/
2743
2744/**
2745 * xmlXPathRoot:
2746 * @ctxt: the XPath Parser context
2747 *
2748 * Initialize the context to the root of the document
2749 */
2750void
2751xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002752 xmlXPathObjectPtr obj;
2753
2754 CHECK_TYPE(XPATH_NODESET);
2755 obj = valuePop(ctxt);
2756
Daniel Veillardb05deb71999-08-10 19:04:08 +00002757 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Daniel Veillard740abf52000-10-02 23:04:54 +00002758
2759 xmlXPathFreeObject(obj);
2760 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002761}
2762
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002763/************************************************************************
2764 * *
2765 * The explicit core function library *
2766 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2767 * *
2768 ************************************************************************/
2769
2770
2771/**
2772 * xmlXPathLastFunction:
2773 * @ctxt: the XPath Parser context
2774 *
2775 * Implement the last() XPath function
2776 * The last function returns the number of nodes in the context node list.
2777 */
2778void
2779xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2780 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002781 if (ctxt->context->contextSize > 0) {
2782 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
2783#ifdef DEBUG_EXPR
2784 fprintf(xmlXPathDebug, "last() : %d\n", ctxt->context->contextSize);
2785#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002786 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002787 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002788 }
2789}
2790
2791/**
2792 * xmlXPathPositionFunction:
2793 * @ctxt: the XPath Parser context
2794 *
2795 * Implement the position() XPath function
2796 * The position function returns the position of the context node in the
2797 * context node list. The first position is 1, and so the last positionr
2798 * will be equal to last().
2799 */
2800void
2801xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002802 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002803 if (ctxt->context->proximityPosition > 0) {
2804 valuePush(ctxt,
2805 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
2806#ifdef DEBUG_EXPR
2807 fprintf(xmlXPathDebug, "position() : %d\n",
2808 ctxt->context->proximityPosition);
2809#endif
2810 } else {
2811 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002812 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002813}
2814
2815/**
2816 * xmlXPathCountFunction:
2817 * @ctxt: the XPath Parser context
2818 *
2819 * Implement the count() XPath function
2820 */
2821void
2822xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2823 xmlXPathObjectPtr cur;
2824
2825 CHECK_ARITY(1);
2826 CHECK_TYPE(XPATH_NODESET);
2827 cur = valuePop(ctxt);
2828
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002829 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002830 xmlXPathFreeObject(cur);
2831}
2832
2833/**
2834 * xmlXPathIdFunction:
2835 * @ctxt: the XPath Parser context
2836 *
2837 * Implement the id() XPath function
2838 * The id function selects elements by their unique ID
2839 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2840 * then the result is the union of the result of applying id to the
2841 * string value of each of the nodes in the argument node-set. When the
2842 * argument to id is of any other type, the argument is converted to a
2843 * string as if by a call to the string function; the string is split
2844 * into a whitespace-separated list of tokens (whitespace is any sequence
2845 * of characters matching the production S); the result is a node-set
2846 * containing the elements in the same document as the context node that
2847 * have a unique ID equal to any of the tokens in the list.
2848 */
2849void
2850xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002851 const xmlChar *tokens;
2852 const xmlChar *cur;
2853 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002854 xmlAttrPtr attr;
2855 xmlNodePtr elem = NULL;
2856 xmlXPathObjectPtr ret, obj;
2857
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002858 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002859 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002860 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002861 if (obj->type == XPATH_NODESET) {
2862 TODO /* ID function in case of NodeSet */
2863 }
2864 if (obj->type != XPATH_STRING) {
2865 valuePush(ctxt, obj);
2866 xmlXPathStringFunction(ctxt, 1);
2867 obj = valuePop(ctxt);
2868 if (obj->type != XPATH_STRING) {
2869 xmlXPathFreeObject(obj);
2870 return;
2871 }
2872 }
2873 tokens = obj->stringval;
2874
2875 ret = xmlXPathNewNodeSet(NULL);
2876 valuePush(ctxt, ret);
2877 if (tokens == NULL) {
2878 xmlXPathFreeObject(obj);
2879 return;
2880 }
2881
2882 cur = tokens;
2883
2884 while (IS_BLANK(*cur)) cur++;
2885 while (*cur != 0) {
2886 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2887 (*cur == '.') || (*cur == '-') ||
2888 (*cur == '_') || (*cur == ':') ||
2889 (IS_COMBINING(*cur)) ||
2890 (IS_EXTENDER(*cur)))
2891 cur++;
2892
2893 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2894
2895 ID = xmlStrndup(tokens, cur - tokens);
2896 attr = xmlGetID(ctxt->context->doc, ID);
2897 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002898 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002899 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2900 }
2901 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002902 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002903
2904 while (IS_BLANK(*cur)) cur++;
2905 tokens = cur;
2906 }
2907 xmlXPathFreeObject(obj);
2908 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002909}
2910
2911/**
2912 * xmlXPathLocalPartFunction:
2913 * @ctxt: the XPath Parser context
2914 *
2915 * Implement the local-part() XPath function
2916 * The local-part function returns a string containing the local part
2917 * of the name of the node in the argument node-set that is first in
2918 * document order. If the node-set is empty or the first node has no
2919 * name, an empty string is returned. If the argument is omitted it
2920 * defaults to the context node.
2921 */
2922void
2923xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2924 xmlXPathObjectPtr cur;
2925
2926 CHECK_ARITY(1);
2927 CHECK_TYPE(XPATH_NODESET);
2928 cur = valuePop(ctxt);
2929
2930 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002931 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002932 } else {
2933 int i = 0; /* Should be first in document order !!!!! */
2934 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2935 }
2936 xmlXPathFreeObject(cur);
2937}
2938
2939/**
2940 * xmlXPathNamespaceFunction:
2941 * @ctxt: the XPath Parser context
2942 *
2943 * Implement the namespace() XPath function
2944 * The namespace function returns a string containing the namespace URI
2945 * of the expanded name of the node in the argument node-set that is
2946 * first in document order. If the node-set is empty, the first node has
2947 * no name, or the expanded name has no namespace URI, an empty string
2948 * is returned. If the argument is omitted it defaults to the context node.
2949 */
2950void
2951xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2952 xmlXPathObjectPtr cur;
2953
Daniel Veillardb96e6431999-08-29 21:02:19 +00002954 if (nargs == 0) {
2955 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2956 nargs = 1;
2957 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002958 CHECK_ARITY(1);
2959 CHECK_TYPE(XPATH_NODESET);
2960 cur = valuePop(ctxt);
2961
2962 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002963 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002964 } else {
2965 int i = 0; /* Should be first in document order !!!!! */
2966
2967 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002968 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002969 else
2970 valuePush(ctxt, xmlXPathNewString(
2971 cur->nodesetval->nodeTab[i]->ns->href));
2972 }
2973 xmlXPathFreeObject(cur);
2974}
2975
2976/**
2977 * xmlXPathNameFunction:
2978 * @ctxt: the XPath Parser context
2979 *
2980 * Implement the name() XPath function
2981 * The name function returns a string containing a QName representing
2982 * the name of the node in the argument node-set that is first in documenti
2983 * order. The QName must represent the name with respect to the namespace
2984 * declarations in effect on the node whose name is being represented.
2985 * Typically, this will be the form in which the name occurred in the XML
2986 * source. This need not be the case if there are namespace declarations
2987 * in effect on the node that associate multiple prefixes with the same
2988 * namespace. However, an implementation may include information about
2989 * the original prefix in its representation of nodes; in this case, an
2990 * implementation can ensure that the returned string is always the same
2991 * as the QName used in the XML source. If the argument it omitted it
2992 * defaults to the context node.
2993 * Libxml keep the original prefix so the "real qualified name" used is
2994 * returned.
2995 */
2996void
2997xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2998 xmlXPathObjectPtr cur;
2999
3000 CHECK_ARITY(1);
3001 CHECK_TYPE(XPATH_NODESET);
3002 cur = valuePop(ctxt);
3003
3004 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003005 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003006 } else {
3007 int i = 0; /* Should be first in document order !!!!! */
3008
3009 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3010 valuePush(ctxt, xmlXPathNewString(
3011 cur->nodesetval->nodeTab[i]->name));
3012
3013 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003014 char name[2000];
Daniel Veillard39c7d712000-09-10 16:14:55 +00003015#ifdef HAVE_SNPRINTF
3016 snprintf(name, sizeof(name), "%s:%s",
3017 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3018 (char *) cur->nodesetval->nodeTab[i]->name);
3019#else
Daniel Veillardb96e6431999-08-29 21:02:19 +00003020 sprintf(name, "%s:%s",
3021 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3022 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003023#endif
3024 name[sizeof(name) - 1] = 0;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003025 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003026 }
3027 }
3028 xmlXPathFreeObject(cur);
3029}
3030
3031/**
3032 * xmlXPathStringFunction:
3033 * @ctxt: the XPath Parser context
3034 *
3035 * Implement the string() XPath function
3036 * he string function converts an object to a string as follows:
3037 * - A node-set is converted to a string by returning the value of
3038 * the node in the node-set that is first in document order.
3039 * If the node-set is empty, an empty string is returned.
3040 * - A number is converted to a string as follows
3041 * + NaN is converted to the string NaN
3042 * + positive zero is converted to the string 0
3043 * + negative zero is converted to the string 0
3044 * + positive infinity is converted to the string Infinity
3045 * + negative infinity is converted to the string -Infinity
3046 * + if the number is an integer, the number is represented in
3047 * decimal form as a Number with no decimal point and no leading
3048 * zeros, preceded by a minus sign (-) if the number is negative
3049 * + otherwise, the number is represented in decimal form as a
3050 * Number including a decimal point with at least one digit
3051 * before the decimal point and at least one digit after the
3052 * decimal point, preceded by a minus sign (-) if the number
3053 * is negative; there must be no leading zeros before the decimal
3054 * point apart possibly from the one required digit immediatelyi
3055 * before the decimal point; beyond the one required digit
3056 * after the decimal point there must be as many, but only as
3057 * many, more digits as are needed to uniquely distinguish the
3058 * number from all other IEEE 754 numeric values.
3059 * - The boolean false value is converted to the string false.
3060 * The boolean true value is converted to the string true.
3061 */
3062void
3063xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3064 xmlXPathObjectPtr cur;
3065
3066 CHECK_ARITY(1);
3067 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003068 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003069 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003070 case XPATH_UNDEFINED:
3071#ifdef DEBUG_EXPR
3072 fprintf(xmlXPathDebug, "String: undefined\n");
3073#endif
3074 valuePush(ctxt, xmlXPathNewCString(""));
3075 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003076 case XPATH_NODESET:
3077 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003078 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003079 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003080 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003081 int i = 0; /* Should be first in document order !!!!! */
3082 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
3083 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003084 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003085 }
3086 xmlXPathFreeObject(cur);
3087 return;
3088 case XPATH_STRING:
3089 valuePush(ctxt, cur);
3090 return;
3091 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003092 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
3093 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003094 xmlXPathFreeObject(cur);
3095 return;
3096 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003097 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003098
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003099 if (isnan(cur->floatval))
3100 sprintf(buf, "NaN");
3101 else if (isinf(cur->floatval) > 0)
3102 sprintf(buf, "+Infinity");
3103 else if (isinf(cur->floatval) < 0)
3104 sprintf(buf, "-Infinity");
3105 else
3106 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003107 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003108 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003109 return;
3110 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003111 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003112 case XPATH_POINT:
3113 case XPATH_RANGE:
3114 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003115 TODO
3116 valuePush(ctxt, xmlXPathNewCString(""));
3117 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003118 }
3119 STRANGE
3120}
3121
3122/**
3123 * xmlXPathStringLengthFunction:
3124 * @ctxt: the XPath Parser context
3125 *
3126 * Implement the string-length() XPath function
3127 * The string-length returns the number of characters in the string
3128 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3129 * the context node converted to a string, in other words the value
3130 * of the context node.
3131 */
3132void
3133xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3134 xmlXPathObjectPtr cur;
3135
3136 if (nargs == 0) {
3137 if (ctxt->context->node == NULL) {
3138 valuePush(ctxt, xmlXPathNewFloat(0));
3139 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003140 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003141
3142 content = xmlNodeGetContent(ctxt->context->node);
3143 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003144 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003145 }
3146 return;
3147 }
3148 CHECK_ARITY(1);
3149 CHECK_TYPE(XPATH_STRING);
3150 cur = valuePop(ctxt);
3151 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3152 xmlXPathFreeObject(cur);
3153}
3154
3155/**
3156 * xmlXPathConcatFunction:
3157 * @ctxt: the XPath Parser context
3158 *
3159 * Implement the concat() XPath function
3160 * The concat function returns the concatenation of its arguments.
3161 */
3162void
3163xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003164 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003165 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003166
3167 if (nargs < 2) {
3168 CHECK_ARITY(2);
3169 }
3170
3171 cur = valuePop(ctxt);
3172 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3173 xmlXPathFreeObject(cur);
3174 return;
3175 }
3176 nargs--;
3177
3178 while (nargs > 0) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003179 newobj = valuePop(ctxt);
3180 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3181 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003182 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003183 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003184 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003185 tmp = xmlStrcat(newobj->stringval, cur->stringval);
3186 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003187 cur->stringval = tmp;
3188
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003189 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003190 nargs--;
3191 }
3192 valuePush(ctxt, cur);
3193}
3194
3195/**
3196 * xmlXPathContainsFunction:
3197 * @ctxt: the XPath Parser context
3198 *
3199 * Implement the contains() XPath function
3200 * The contains function returns true if the first argument string
3201 * contains the second argument string, and otherwise returns false.
3202 */
3203void
3204xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3205 xmlXPathObjectPtr hay, needle;
3206
3207 CHECK_ARITY(2);
3208 CHECK_TYPE(XPATH_STRING);
3209 needle = valuePop(ctxt);
3210 hay = valuePop(ctxt);
3211 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3212 xmlXPathFreeObject(hay);
3213 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003214 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003215 }
3216 if (xmlStrstr(hay->stringval, needle->stringval))
3217 valuePush(ctxt, xmlXPathNewBoolean(1));
3218 else
3219 valuePush(ctxt, xmlXPathNewBoolean(0));
3220 xmlXPathFreeObject(hay);
3221 xmlXPathFreeObject(needle);
3222}
3223
3224/**
3225 * xmlXPathStartsWithFunction:
3226 * @ctxt: the XPath Parser context
3227 *
3228 * Implement the starts-with() XPath function
3229 * The starts-with function returns true if the first argument string
3230 * starts with the second argument string, and otherwise returns false.
3231 */
3232void
3233xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3234 xmlXPathObjectPtr hay, needle;
3235 int n;
3236
3237 CHECK_ARITY(2);
3238 CHECK_TYPE(XPATH_STRING);
3239 needle = valuePop(ctxt);
3240 hay = valuePop(ctxt);
3241 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3242 xmlXPathFreeObject(hay);
3243 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003244 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003245 }
3246 n = xmlStrlen(needle->stringval);
3247 if (xmlStrncmp(hay->stringval, needle->stringval, n))
3248 valuePush(ctxt, xmlXPathNewBoolean(0));
3249 else
3250 valuePush(ctxt, xmlXPathNewBoolean(1));
3251 xmlXPathFreeObject(hay);
3252 xmlXPathFreeObject(needle);
3253}
3254
3255/**
3256 * xmlXPathSubstringFunction:
3257 * @ctxt: the XPath Parser context
3258 *
3259 * Implement the substring() XPath function
3260 * The substring function returns the substring of the first argument
3261 * starting at the position specified in the second argument with
3262 * length specified in the third argument. For example,
3263 * substring("12345",2,3) returns "234". If the third argument is not
3264 * specified, it returns the substring starting at the position specified
3265 * in the second argument and continuing to the end of the string. For
3266 * example, substring("12345",2) returns "2345". More precisely, each
3267 * character in the string (see [3.6 Strings]) is considered to have a
3268 * numeric position: the position of the first character is 1, the position
3269 * of the second character is 2 and so on. The returned substring contains
3270 * those characters for which the position of the character is greater than
3271 * or equal to the second argument and, if the third argument is specified,
3272 * less than the sum of the second and third arguments; the comparisons
3273 * and addition used for the above follow the standard IEEE 754 rules. Thus:
3274 * - substring("12345", 1.5, 2.6) returns "234"
3275 * - substring("12345", 0, 3) returns "12"
3276 * - substring("12345", 0 div 0, 3) returns ""
3277 * - substring("12345", 1, 0 div 0) returns ""
3278 * - substring("12345", -42, 1 div 0) returns "12345"
3279 * - substring("12345", -1 div 0, 1 div 0) returns ""
3280 */
3281void
3282xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3283 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003284 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003285 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003286 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003287
3288 /*
3289 * Conformance needs to be checked !!!!!
3290 */
3291 if (nargs < 2) {
3292 CHECK_ARITY(2);
3293 }
3294 if (nargs > 3) {
3295 CHECK_ARITY(3);
3296 }
3297 if (nargs == 3) {
3298 CHECK_TYPE(XPATH_NUMBER);
3299 len = valuePop(ctxt);
3300 le = len->floatval;
3301 xmlXPathFreeObject(len);
3302 } else {
3303 le = 2000000000;
3304 }
3305 CHECK_TYPE(XPATH_NUMBER);
3306 start = valuePop(ctxt);
3307 in = start->floatval;
3308 xmlXPathFreeObject(start);
3309 CHECK_TYPE(XPATH_STRING);
3310 str = valuePop(ctxt);
3311 le += in;
3312
3313 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003314 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003315 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003316
3317 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003318 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003319 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003320
3321 /* back to a zero based len */
3322 i--;
3323 l--;
3324
3325 /* check against the string len */
3326 if (l > 1024) {
3327 l = xmlStrlen(str->stringval);
3328 }
3329 if (i < 0) {
3330 i = 0;
3331 }
3332
3333 /* number of chars to copy */
3334 l -= i;
3335
3336 ret = xmlStrsub(str->stringval, i, l);
3337 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00003338 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003339 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003340 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003341 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003342 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003343 xmlXPathFreeObject(str);
3344}
3345
3346/**
3347 * xmlXPathSubstringBeforeFunction:
3348 * @ctxt: the XPath Parser context
3349 *
3350 * Implement the substring-before() XPath function
3351 * The substring-before function returns the substring of the first
3352 * argument string that precedes the first occurrence of the second
3353 * argument string in the first argument string, or the empty string
3354 * if the first argument string does not contain the second argument
3355 * string. For example, substring-before("1999/04/01","/") returns 1999.
3356 */
3357void
3358xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003359 xmlXPathObjectPtr str;
3360 xmlXPathObjectPtr find;
3361 xmlBufferPtr target;
3362 const xmlChar *point;
3363 int offset;
3364
3365 CHECK_ARITY(2);
3366 find = valuePop(ctxt);
3367 str = valuePop(ctxt);
3368
3369 target = xmlBufferCreate();
3370 if (target) {
3371 point = xmlStrstr(str->stringval, find->stringval);
3372 if (point) {
3373 offset = (int)(point - str->stringval);
3374 xmlBufferAdd(target, str->stringval, offset);
3375 }
3376 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3377 xmlBufferFree(target);
3378 }
3379
3380 xmlXPathFreeObject(str);
3381 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003382}
3383
3384/**
3385 * xmlXPathSubstringAfterFunction:
3386 * @ctxt: the XPath Parser context
3387 *
3388 * Implement the substring-after() XPath function
3389 * The substring-after function returns the substring of the first
3390 * argument string that follows the first occurrence of the second
3391 * argument string in the first argument string, or the empty stringi
3392 * if the first argument string does not contain the second argument
3393 * string. For example, substring-after("1999/04/01","/") returns 04/01,
3394 * and substring-after("1999/04/01","19") returns 99/04/01.
3395 */
3396void
3397xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003398 xmlXPathObjectPtr str;
3399 xmlXPathObjectPtr find;
3400 xmlBufferPtr target;
3401 const xmlChar *point;
3402 int offset;
3403
3404 CHECK_ARITY(2);
3405 find = valuePop(ctxt);
3406 str = valuePop(ctxt);
3407
3408 target = xmlBufferCreate();
3409 if (target) {
3410 point = xmlStrstr(str->stringval, find->stringval);
3411 if (point) {
3412 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
3413 xmlBufferAdd(target, &str->stringval[offset],
3414 xmlStrlen(str->stringval) - offset);
3415 }
3416 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3417 xmlBufferFree(target);
3418 }
3419
3420 xmlXPathFreeObject(str);
3421 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003422}
3423
3424/**
3425 * xmlXPathNormalizeFunction:
3426 * @ctxt: the XPath Parser context
3427 *
3428 * Implement the normalize() XPath function
3429 * The normalize function returns the argument string with white
3430 * space normalized by stripping leading and trailing whitespace
3431 * and replacing sequences of whitespace characters by a single
3432 * space. Whitespace characters are the same allowed by the S production
3433 * in XML. If the argument is omitted, it defaults to the context
3434 * node converted to a string, in other words the value of the context node.
3435 */
3436void
3437xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003438 xmlXPathObjectPtr obj = NULL;
3439 xmlChar *source = NULL;
3440 xmlBufferPtr target;
3441 xmlChar blank;
3442
3443 if (nargs < 1) {
3444 /* Use current context node */
3445 CHECK_ARITY(0);
3446 TODO /* source = xmlNodeGetContent(ctxt->context->node); */
3447 } else if (nargs >= 1) {
3448 /* Use argument */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003449 CHECK_ARITY(1);
Daniel Veillard46057e12000-09-24 18:49:59 +00003450 obj = valuePop(ctxt);
3451 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3452 source = obj->stringval;
3453 }
3454 target = xmlBufferCreate();
3455 if (target && source) {
3456
3457 /* Skip leading whitespaces */
3458 while (IS_BLANK(*source))
3459 source++;
3460
3461 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
3462 blank = 0;
3463 while (*source) {
3464 if (IS_BLANK(*source)) {
3465 blank = *source;
3466 } else {
3467 if (blank) {
3468 xmlBufferAdd(target, &blank, 1);
3469 blank = 0;
3470 }
3471 xmlBufferAdd(target, source, 1);
3472 }
3473 source++;
3474 }
3475
3476 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3477 xmlBufferFree(target);
3478 }
3479 if (obj)
3480 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003481}
3482
3483/**
3484 * xmlXPathTranslateFunction:
3485 * @ctxt: the XPath Parser context
3486 *
3487 * Implement the translate() XPath function
3488 * The translate function returns the first argument string with
3489 * occurrences of characters in the second argument string replaced
3490 * by the character at the corresponding position in the third argument
3491 * string. For example, translate("bar","abc","ABC") returns the string
3492 * BAr. If there is a character in the second argument string with no
3493 * character at a corresponding position in the third argument string
3494 * (because the second argument string is longer than the third argument
3495 * string), then occurrences of that character in the first argument
3496 * string are removed. For example, translate("--aaa--","abc-","ABC")
3497 * returns "AAA". If a character occurs more than once in second
3498 * argument string, then the first occurrence determines the replacement
3499 * character. If the third argument string is longer than the second
3500 * argument string, then excess characters are ignored.
3501 */
3502void
3503xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003504 xmlXPathObjectPtr str;
3505 xmlXPathObjectPtr from;
3506 xmlXPathObjectPtr to;
3507 xmlBufferPtr target;
3508 int i, offset, max;
3509 xmlChar ch;
3510 const xmlChar *point;
3511
3512 CHECK_ARITY(3);
3513
3514 to = valuePop(ctxt);
3515 from = valuePop(ctxt);
3516 str = valuePop(ctxt);
3517
3518 target = xmlBufferCreate();
3519 if (target) {
3520 max = xmlStrlen(to->stringval);
3521 for (i = 0; (ch = str->stringval[i]); i++) {
3522 point = xmlStrchr(from->stringval, ch);
3523 if (point) {
3524 /* Warning: This may not work with UTF-8 */
3525 offset = (int)(point - from->stringval);
3526 if (offset < max)
3527 xmlBufferAdd(target, &to->stringval[offset], 1);
3528 } else
3529 xmlBufferAdd(target, &ch, 1);
3530 }
3531 }
3532 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3533 xmlBufferFree(target);
3534 xmlXPathFreeObject(str);
3535 xmlXPathFreeObject(from);
3536 xmlXPathFreeObject(to);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003537}
3538
3539/**
3540 * xmlXPathBooleanFunction:
3541 * @ctxt: the XPath Parser context
3542 *
3543 * Implement the boolean() XPath function
3544 * he boolean function converts its argument to a boolean as follows:
3545 * - a number is true if and only if it is neither positive or
3546 * negative zero nor NaN
3547 * - a node-set is true if and only if it is non-empty
3548 * - a string is true if and only if its length is non-zero
3549 */
3550void
3551xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3552 xmlXPathObjectPtr cur;
3553 int res = 0;
3554
3555 CHECK_ARITY(1);
3556 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003557 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003558 switch (cur->type) {
3559 case XPATH_NODESET:
3560 if ((cur->nodesetval == NULL) ||
3561 (cur->nodesetval->nodeNr == 0)) res = 0;
3562 else
3563 res = 1;
3564 break;
3565 case XPATH_STRING:
3566 if ((cur->stringval == NULL) ||
3567 (cur->stringval[0] == 0)) res = 0;
3568 else
3569 res = 1;
3570 break;
3571 case XPATH_BOOLEAN:
3572 valuePush(ctxt, cur);
3573 return;
3574 case XPATH_NUMBER:
3575 if (cur->floatval) res = 1;
3576 break;
3577 default:
3578 STRANGE
3579 }
3580 xmlXPathFreeObject(cur);
3581 valuePush(ctxt, xmlXPathNewBoolean(res));
3582}
3583
3584/**
3585 * xmlXPathNotFunction:
3586 * @ctxt: the XPath Parser context
3587 *
3588 * Implement the not() XPath function
3589 * The not function returns true if its argument is false,
3590 * and false otherwise.
3591 */
3592void
3593xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3594 CHECK_ARITY(1);
3595 CHECK_TYPE(XPATH_BOOLEAN);
3596 ctxt->value->boolval = ! ctxt->value->boolval;
3597}
3598
3599/**
3600 * xmlXPathTrueFunction:
3601 * @ctxt: the XPath Parser context
3602 *
3603 * Implement the true() XPath function
3604 */
3605void
3606xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3607 CHECK_ARITY(0);
3608 valuePush(ctxt, xmlXPathNewBoolean(1));
3609}
3610
3611/**
3612 * xmlXPathFalseFunction:
3613 * @ctxt: the XPath Parser context
3614 *
3615 * Implement the false() XPath function
3616 */
3617void
3618xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3619 CHECK_ARITY(0);
3620 valuePush(ctxt, xmlXPathNewBoolean(0));
3621}
3622
3623/**
3624 * xmlXPathLangFunction:
3625 * @ctxt: the XPath Parser context
3626 *
3627 * Implement the lang() XPath function
3628 * The lang function returns true or false depending on whether the
3629 * language of the context node as specified by xml:lang attributes
3630 * is the same as or is a sublanguage of the language specified by
3631 * the argument string. The language of the context node is determined
3632 * by the value of the xml:lang attribute on the context node, or, if
3633 * the context node has no xml:lang attribute, by the value of the
3634 * xml:lang attribute on the nearest ancestor of the context node that
3635 * has an xml:lang attribute. If there is no such attribute, then lang
3636 * returns false. If there is such an attribute, then lang returns
3637 * true if the attribute value is equal to the argument ignoring case,
3638 * or if there is some suffix starting with - such that the attribute
3639 * value is equal to the argument ignoring that suffix of the attribute
3640 * value and ignoring case.
3641 */
3642void
3643xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003644 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003645 const xmlChar *theLang;
3646 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003647 int ret = 0;
3648 int i;
3649
3650 CHECK_ARITY(1);
3651 CHECK_TYPE(XPATH_STRING);
3652 val = valuePop(ctxt);
3653 lang = val->stringval;
3654 theLang = xmlNodeGetLang(ctxt->context->node);
3655 if ((theLang != NULL) && (lang != NULL)) {
3656 for (i = 0;lang[i] != 0;i++)
3657 if (toupper(lang[i]) != toupper(theLang[i]))
3658 goto not_equal;
3659 ret = 1;
3660 }
3661not_equal:
3662 xmlXPathFreeObject(val);
3663 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003664}
3665
3666/**
3667 * xmlXPathNumberFunction:
3668 * @ctxt: the XPath Parser context
3669 *
3670 * Implement the number() XPath function
3671 */
3672void
3673xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3674 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003675 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003676
3677 CHECK_ARITY(1);
3678 cur = valuePop(ctxt);
3679 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003680 case XPATH_UNDEFINED:
3681#ifdef DEBUG_EXPR
3682 fprintf(xmlXPathDebug, "NUMBER: undefined\n");
3683#endif
3684 valuePush(ctxt, xmlXPathNewFloat(0.0));
3685 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003686 case XPATH_NODESET:
3687 valuePush(ctxt, cur);
3688 xmlXPathStringFunction(ctxt, 1);
3689 cur = valuePop(ctxt);
3690 case XPATH_STRING:
3691 res = xmlXPathStringEvalNumber(cur->stringval);
3692 valuePush(ctxt, xmlXPathNewFloat(res));
3693 xmlXPathFreeObject(cur);
3694 return;
3695 case XPATH_BOOLEAN:
3696 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
3697 else valuePush(ctxt, xmlXPathNewFloat(0.0));
3698 xmlXPathFreeObject(cur);
3699 return;
3700 case XPATH_NUMBER:
3701 valuePush(ctxt, cur);
3702 return;
Daniel Veillard740abf52000-10-02 23:04:54 +00003703 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003704 case XPATH_POINT:
3705 case XPATH_RANGE:
3706 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003707 TODO
3708 valuePush(ctxt, xmlXPathNewFloat(0.0));
3709 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003710 }
3711 STRANGE
3712}
3713
3714/**
3715 * xmlXPathSumFunction:
3716 * @ctxt: the XPath Parser context
3717 *
3718 * Implement the sum() XPath function
3719 * The sum function returns the sum of the values of the nodes in
3720 * the argument node-set.
3721 */
3722void
3723xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3724 CHECK_ARITY(1);
3725 TODO /* BUG Sum : don't understand the definition */
3726}
3727
3728/**
3729 * xmlXPathFloorFunction:
3730 * @ctxt: the XPath Parser context
3731 *
3732 * Implement the floor() XPath function
3733 * The floor function returns the largest (closest to positive infinity)
3734 * number that is not greater than the argument and that is an integer.
3735 */
3736void
3737xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3738 CHECK_ARITY(1);
3739 CHECK_TYPE(XPATH_NUMBER);
3740 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003741 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003742}
3743
3744/**
3745 * xmlXPathCeilingFunction:
3746 * @ctxt: the XPath Parser context
3747 *
3748 * Implement the ceiling() XPath function
3749 * The ceiling function returns the smallest (closest to negative infinity)
3750 * number that is not less than the argument and that is an integer.
3751 */
3752void
3753xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003754 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003755
3756 CHECK_ARITY(1);
3757 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003758 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003759 if (f != ctxt->value->floatval)
3760 ctxt->value->floatval = f + 1;
3761}
3762
3763/**
3764 * xmlXPathRoundFunction:
3765 * @ctxt: the XPath Parser context
3766 *
3767 * Implement the round() XPath function
3768 * The round function returns the number that is closest to the
3769 * argument and that is an integer. If there are two such numbers,
3770 * then the one that is even is returned.
3771 */
3772void
3773xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003774 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003775
3776 CHECK_ARITY(1);
3777 CHECK_TYPE(XPATH_NUMBER);
3778 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003779 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003780 if (ctxt->value->floatval < f + 0.5)
3781 ctxt->value->floatval = f;
3782 else if (ctxt->value->floatval == f + 0.5)
3783 ctxt->value->floatval = f; /* !!!! Not following the spec here */
3784 else
3785 ctxt->value->floatval = f + 1;
3786}
3787
3788/************************************************************************
3789 * *
3790 * The Parser *
3791 * *
3792 ************************************************************************/
3793
3794/*
3795 * a couple of forward declarations since we use a recursive call based
3796 * implementation.
3797 */
3798void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3799void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3800void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3801void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3802
3803/**
3804 * xmlXPathParseNCName:
3805 * @ctxt: the XPath Parser context
3806 *
3807 * parse an XML namespace non qualified name.
3808 *
3809 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3810 *
3811 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3812 * CombiningChar | Extender
3813 *
3814 * Returns the namespace name or NULL
3815 */
3816
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003817xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003818xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003819 const xmlChar *q;
3820 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003821
3822 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3823 q = NEXT;
3824
3825 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3826 (CUR == '.') || (CUR == '-') ||
3827 (CUR == '_') ||
3828 (IS_COMBINING(CUR)) ||
3829 (IS_EXTENDER(CUR)))
3830 NEXT;
3831
3832 ret = xmlStrndup(q, CUR_PTR - q);
3833
3834 return(ret);
3835}
3836
3837/**
3838 * xmlXPathParseQName:
3839 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003840 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003841 *
3842 * parse an XML qualified name
3843 *
3844 * [NS 5] QName ::= (Prefix ':')? LocalPart
3845 *
3846 * [NS 6] Prefix ::= NCName
3847 *
3848 * [NS 7] LocalPart ::= NCName
3849 *
3850 * Returns the function returns the local part, and prefix is updated
3851 * to get the Prefix if any.
3852 */
3853
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003854xmlChar *
3855xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3856 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003857
3858 *prefix = NULL;
3859 ret = xmlXPathParseNCName(ctxt);
3860 if (CUR == ':') {
3861 *prefix = ret;
3862 NEXT;
3863 ret = xmlXPathParseNCName(ctxt);
3864 }
3865 return(ret);
3866}
3867
3868/**
3869 * xmlXPathStringEvalNumber:
3870 * @str: A string to scan
3871 *
3872 * [30] Number ::= Digits ('.' Digits)?
3873 * | '.' Digits
3874 * [31] Digits ::= [0-9]+
3875 *
3876 * Parse and evaluate a Number in the string
3877 *
3878 * BUG: "1.' is not valid ... James promised correction
3879 * as Digits ('.' Digits?)?
3880 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003881 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003882 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003883double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003884xmlXPathStringEvalNumber(const xmlChar *str) {
3885 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003886 double ret = 0.0;
3887 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003888 int ok = 0;
3889
3890 while (*cur == ' ') cur++;
3891 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003892 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003893 }
3894 while ((*cur >= '0') && (*cur <= '9')) {
3895 ret = ret * 10 + (*cur - '0');
3896 ok = 1;
3897 cur++;
3898 }
3899 if (*cur == '.') {
3900 cur++;
3901 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003902 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003903 }
3904 while ((*cur >= '0') && (*cur <= '9')) {
3905 mult /= 10;
3906 ret = ret + (*cur - '0') * mult;
3907 cur++;
3908 }
3909 }
3910 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003911 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003912 return(ret);
3913}
3914
3915/**
3916 * xmlXPathEvalNumber:
3917 * @ctxt: the XPath Parser context
3918 *
3919 * [30] Number ::= Digits ('.' Digits)?
3920 * | '.' Digits
3921 * [31] Digits ::= [0-9]+
3922 *
3923 * Parse and evaluate a Number, then push it on the stack
3924 *
3925 * BUG: "1.' is not valid ... James promised correction
3926 * as Digits ('.' Digits?)?
3927 */
3928void
3929xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003930 double ret = 0.0;
3931 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003932 int ok = 0;
3933
3934 CHECK_ERROR;
3935 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003936 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003937 }
3938 while ((CUR >= '0') && (CUR <= '9')) {
3939 ret = ret * 10 + (CUR - '0');
3940 ok = 1;
3941 NEXT;
3942 }
3943 if (CUR == '.') {
3944 NEXT;
3945 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003946 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003947 }
3948 while ((CUR >= '0') && (CUR <= '9')) {
3949 mult /= 10;
3950 ret = ret + (CUR - '0') * mult;
3951 NEXT;
3952 }
3953 }
3954 valuePush(ctxt, xmlXPathNewFloat(ret));
3955}
3956
3957/**
3958 * xmlXPathEvalLiteral:
3959 * @ctxt: the XPath Parser context
3960 *
3961 * Parse a Literal and push it on the stack.
3962 *
3963 * [29] Literal ::= '"' [^"]* '"'
3964 * | "'" [^']* "'"
3965 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003966 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003967 */
3968void
3969xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003970 const xmlChar *q;
3971 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003972
3973 if (CUR == '"') {
3974 NEXT;
3975 q = CUR_PTR;
3976 while ((IS_CHAR(CUR)) && (CUR != '"'))
3977 NEXT;
3978 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003979 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003980 } else {
3981 ret = xmlStrndup(q, CUR_PTR - q);
3982 NEXT;
3983 }
3984 } else if (CUR == '\'') {
3985 NEXT;
3986 q = CUR_PTR;
3987 while ((IS_CHAR(CUR)) && (CUR != '\''))
3988 NEXT;
3989 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003990 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003991 } else {
3992 ret = xmlStrndup(q, CUR_PTR - q);
3993 NEXT;
3994 }
3995 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003996 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003997 }
3998 if (ret == NULL) return;
3999 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004000 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004001}
4002
4003/**
4004 * xmlXPathEvalVariableReference:
4005 * @ctxt: the XPath Parser context
4006 *
4007 * Parse a VariableReference, evaluate it and push it on the stack.
4008 *
4009 * The variable bindings consist of a mapping from variable names
4010 * to variable values. The value of a variable is an object, which
4011 * of any of the types that are possible for the value of an expression,
4012 * and may also be of additional types not specified here.
4013 *
4014 * Early evaluation is possible since:
4015 * The variable bindings [...] used to evaluate a subexpression are
4016 * always the same as those used to evaluate the containing expression.
4017 *
4018 * [36] VariableReference ::= '$' QName
4019 */
4020void
4021xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004022 xmlChar *name;
4023 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004024 xmlXPathObjectPtr value;
4025
4026 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004027 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004028 }
4029 name = xmlXPathParseQName(ctxt, &prefix);
4030 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004031 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004032 }
4033 value = xmlXPathVariablelookup(ctxt, prefix, name);
4034 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004035 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004036 }
4037 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004038 if (prefix != NULL) xmlFree(prefix);
4039 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004040}
4041
4042
4043/**
4044 * xmlXPathFunctionLookup:
4045 * @ctxt: the XPath Parser context
4046 * @name: a name string
4047 *
4048 * Search for a function of the given name
4049 *
4050 * [35] FunctionName ::= QName - NodeType
4051 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004052 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004053 *
4054 * Returns the xmlXPathFunction if found, or NULL otherwise
4055 */
4056xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004057xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004058 switch (name[0]) {
4059 case 'b':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004060 if (xmlStrEqual(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004061 return(xmlXPathBooleanFunction);
4062 break;
4063 case 'c':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004064 if (xmlStrEqual(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004065 return(xmlXPathCeilingFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004066 if (xmlStrEqual(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004067 return(xmlXPathCountFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004068 if (xmlStrEqual(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004069 return(xmlXPathConcatFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004070 if (xmlStrEqual(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004071 return(xmlXPathContainsFunction);
4072 break;
4073 case 'i':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004074 if (xmlStrEqual(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004075 return(xmlXPathIdFunction);
4076 break;
4077 case 'f':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004078 if (xmlStrEqual(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004079 return(xmlXPathFalseFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004080 if (xmlStrEqual(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004081 return(xmlXPathFloorFunction);
4082 break;
4083 case 'l':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004084 if (xmlStrEqual(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004085 return(xmlXPathLastFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004086 if (xmlStrEqual(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004087 return(xmlXPathLangFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004088 if (xmlStrEqual(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004089 return(xmlXPathLocalPartFunction);
4090 break;
4091 case 'n':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004092 if (xmlStrEqual(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004093 return(xmlXPathNotFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004094 if (xmlStrEqual(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004095 return(xmlXPathNameFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004096 if (xmlStrEqual(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004097 return(xmlXPathNamespaceFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004098 if (xmlStrEqual(name, BAD_CAST "normalize-space"))
Daniel Veillard00fdf371999-10-08 09:40:39 +00004099 return(xmlXPathNormalizeFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004100 if (xmlStrEqual(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004101 return(xmlXPathNormalizeFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004102 if (xmlStrEqual(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004103 return(xmlXPathNumberFunction);
4104 break;
4105 case 'p':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004106 if (xmlStrEqual(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004107 return(xmlXPathPositionFunction);
4108 break;
4109 case 'r':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004110 if (xmlStrEqual(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004111 return(xmlXPathRoundFunction);
4112 break;
4113 case 's':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004114 if (xmlStrEqual(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004115 return(xmlXPathStringFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004116 if (xmlStrEqual(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004117 return(xmlXPathStringLengthFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004118 if (xmlStrEqual(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004119 return(xmlXPathStartsWithFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004120 if (xmlStrEqual(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004121 return(xmlXPathSubstringFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004122 if (xmlStrEqual(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004123 return(xmlXPathSubstringBeforeFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004124 if (xmlStrEqual(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004125 return(xmlXPathSubstringAfterFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004126 if (xmlStrEqual(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004127 return(xmlXPathSumFunction);
4128 break;
4129 case 't':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004130 if (xmlStrEqual(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004131 return(xmlXPathTrueFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004132 if (xmlStrEqual(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004133 return(xmlXPathTranslateFunction);
4134 break;
4135 }
4136 return(NULL);
4137}
4138
4139/**
4140 * xmlXPathEvalLocationPathName:
4141 * @ctxt: the XPath Parser context
4142 * @name: a name string
4143 *
4144 * Various names in the beginning of a LocationPath expression
4145 * indicate whether that's an Axis, a node type,
4146 *
4147 * [6] AxisName ::= 'ancestor'
4148 * | 'ancestor-or-self'
4149 * | 'attribute'
4150 * | 'child'
4151 * | 'descendant'
4152 * | 'descendant-or-self'
4153 * | 'following'
4154 * | 'following-sibling'
4155 * | 'namespace'
4156 * | 'parent'
4157 * | 'preceding'
4158 * | 'preceding-sibling'
4159 * | 'self'
4160 * [38] NodeType ::= 'comment'
4161 * | 'text'
4162 * | 'processing-instruction'
4163 * | 'node'
4164 */
4165int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004166xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004167 switch (name[0]) {
4168 case 'a':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004169 if (xmlStrEqual(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
4170 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
Daniel Veillardb96e6431999-08-29 21:02:19 +00004171 return(AXIS_ANCESTOR_OR_SELF);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004172 if (xmlStrEqual(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004173 break;
4174 case 'c':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004175 if (xmlStrEqual(name, BAD_CAST "child")) return(AXIS_CHILD);
4176 if (xmlStrEqual(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004177 break;
4178 case 'd':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004179 if (xmlStrEqual(name, BAD_CAST "descendant"))
Daniel Veillardb96e6431999-08-29 21:02:19 +00004180 return(AXIS_DESCENDANT);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004181 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
Daniel Veillardb96e6431999-08-29 21:02:19 +00004182 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004183 break;
4184 case 'f':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004185 if (xmlStrEqual(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
4186 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
Daniel Veillardb96e6431999-08-29 21:02:19 +00004187 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004188 break;
4189 case 'n':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004190 if (xmlStrEqual(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
4191 if (xmlStrEqual(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004192 break;
4193 case 'p':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004194 if (xmlStrEqual(name, BAD_CAST "parent")) return(AXIS_PARENT);
4195 if (xmlStrEqual(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
4196 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
Daniel Veillardb96e6431999-08-29 21:02:19 +00004197 return(AXIS_PRECEDING_SIBLING);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004198 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Daniel Veillardb96e6431999-08-29 21:02:19 +00004199 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004200 break;
4201 case 's':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004202 if (xmlStrEqual(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004203 break;
4204 case 't':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004205 if (xmlStrEqual(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004206 break;
4207 }
4208 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
4209 return(0);
4210}
4211
4212/**
4213 * xmlXPathEvalFunctionCall:
4214 * @ctxt: the XPath Parser context
4215 *
4216 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4217 * [17] Argument ::= Expr
4218 *
4219 * Parse and evaluate a function call, the evaluation of all arguments are
4220 * pushed on the stack
4221 */
4222void
4223xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004224 xmlChar *name;
4225 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004226 xmlXPathFunction func;
4227 int nbargs = 0;
4228
4229 name = xmlXPathParseQName(ctxt, &prefix);
4230 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004231 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004232 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004233 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004234 func = xmlXPathIsFunction(ctxt, name);
4235 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004236 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004237 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004238 }
4239#ifdef DEBUG_EXPR
4240 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4241#endif
4242
4243 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004244 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004245 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004246 }
4247 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004248 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004249
4250 while (CUR != ')') {
4251 xmlXPathEvalExpr(ctxt);
4252 nbargs++;
4253 if (CUR == ')') break;
4254 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004255 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004256 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004257 }
4258 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004259 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004260 }
4261 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004262 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004263 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004264 func(ctxt, nbargs);
4265}
4266
4267/**
4268 * xmlXPathEvalPrimaryExpr:
4269 * @ctxt: the XPath Parser context
4270 *
4271 * [15] PrimaryExpr ::= VariableReference
4272 * | '(' Expr ')'
4273 * | Literal
4274 * | Number
4275 * | FunctionCall
4276 *
4277 * Parse and evaluate a primary expression, then push the result on the stack
4278 */
4279void
4280xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004281 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004282 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4283 else if (CUR == '(') {
4284 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004285 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004286 xmlXPathEvalExpr(ctxt);
4287 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004288 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004289 }
4290 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004291 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004292 } else if (IS_DIGIT(CUR)) {
4293 xmlXPathEvalNumber(ctxt);
4294 } else if ((CUR == '\'') || (CUR == '"')) {
4295 xmlXPathEvalLiteral(ctxt);
4296 } else {
4297 xmlXPathEvalFunctionCall(ctxt);
4298 }
4299}
4300
4301/**
4302 * xmlXPathEvalFilterExpr:
4303 * @ctxt: the XPath Parser context
4304 *
4305 * [20] FilterExpr ::= PrimaryExpr
4306 * | FilterExpr Predicate
4307 *
4308 * Parse and evaluate a filter expression, then push the result on the stack
4309 * Square brackets are used to filter expressions in the same way that
4310 * they are used in location paths. It is an error if the expression to
4311 * be filtered does not evaluate to a node-set. The context node list
4312 * used for evaluating the expression in square brackets is the node-set
4313 * to be filtered listed in document order.
4314 */
4315
4316void
4317xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
4318 /****
4319 xmlNodeSetPtr oldset = NULL;
4320 xmlXPathObjectPtr arg;
4321 ****/
4322
4323 xmlXPathEvalPrimaryExpr(ctxt);
4324 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004325 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004326
4327 if (CUR != '[') return;
4328
4329 CHECK_TYPE(XPATH_NODESET);
4330
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004331 while (CUR == '[') {
4332 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004333 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004334 }
4335
4336
4337}
4338
4339/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00004340 * xmlXPathScanName:
4341 * @ctxt: the XPath Parser context
4342 *
4343 * Trickery: parse an XML name but without consuming the input flow
4344 * Needed for rollback cases.
4345 *
4346 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4347 * CombiningChar | Extender
4348 *
4349 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4350 *
4351 * [6] Names ::= Name (S Name)*
4352 *
4353 * Returns the Name parsed or NULL
4354 */
4355
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004356xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004357xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004358 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00004359 int len = 0;
4360
Daniel Veillard00fdf371999-10-08 09:40:39 +00004361 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004362 if (!IS_LETTER(CUR) && (CUR != '_') &&
4363 (CUR != ':')) {
4364 return(NULL);
4365 }
4366
4367 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4368 (NXT(len) == '.') || (NXT(len) == '-') ||
4369 (NXT(len) == '_') || (NXT(len) == ':') ||
4370 (IS_COMBINING(NXT(len))) ||
4371 (IS_EXTENDER(NXT(len)))) {
4372 buf[len] = NXT(len);
4373 len++;
4374 if (len >= XML_MAX_NAMELEN) {
4375 fprintf(stderr,
4376 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
4377 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4378 (NXT(len) == '.') || (NXT(len) == '-') ||
4379 (NXT(len) == '_') || (NXT(len) == ':') ||
4380 (IS_COMBINING(NXT(len))) ||
4381 (IS_EXTENDER(NXT(len))))
4382 len++;
4383 break;
4384 }
4385 }
4386 return(xmlStrndup(buf, len));
4387}
4388
4389/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004390 * xmlXPathEvalPathExpr:
4391 * @ctxt: the XPath Parser context
4392 *
4393 * [19] PathExpr ::= LocationPath
4394 * | FilterExpr
4395 * | FilterExpr '/' RelativeLocationPath
4396 * | FilterExpr '//' RelativeLocationPath
4397 *
4398 * Parse and evaluate a path expression, then push the result on the stack
4399 * The / operator and // operators combine an arbitrary expression
4400 * and a relative location path. It is an error if the expression
4401 * does not evaluate to a node-set.
4402 * The / operator does composition in the same way as when / is
4403 * used in a location path. As in location paths, // is short for
4404 * /descendant-or-self::node()/.
4405 */
4406
4407void
4408xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004409 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004410 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
4411 (CUR == '\'') || (CUR == '"')) {
4412 xmlXPathEvalFilterExpr(ctxt);
4413 CHECK_ERROR;
4414 if ((CUR == '/') && (NXT(1) == '/')) {
4415 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004416 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00004417 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004418 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004419 ctxt->context->node = NULL;
4420 xmlXPathEvalRelativeLocationPath(ctxt);
4421 } else if (CUR == '/') {
4422 xmlXPathEvalRelativeLocationPath(ctxt);
4423 }
4424 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004425 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004426 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004427
4428 name = xmlXPathScanName(ctxt);
4429 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
4430 xmlXPathEvalLocationPath(ctxt);
4431 else
4432 xmlXPathEvalFilterExpr(ctxt);
4433 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004434 xmlFree(name);
Daniel Veillardbe803962000-06-28 23:40:59 +00004435
Daniel Veillard740abf52000-10-02 23:04:54 +00004436#if 0
4437 /* DV 1234 !!!!!!! */
4438 if (ctxt->context->nodelist != NULL)
4439 valuePush(ctxt, xmlXPathNewNodeSetList(ctxt->context->nodelist));
4440#endif
Daniel Veillardbe803962000-06-28 23:40:59 +00004441 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004442}
4443
4444/**
4445 * xmlXPathEvalUnionExpr:
4446 * @ctxt: the XPath Parser context
4447 *
4448 * [18] UnionExpr ::= PathExpr
4449 * | UnionExpr '|' PathExpr
4450 *
4451 * Parse and evaluate an union expression, then push the result on the stack
4452 */
4453
4454void
4455xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
4456 xmlXPathEvalPathExpr(ctxt);
4457 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004458 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004459 if (CUR == '|') {
Daniel Veillard740abf52000-10-02 23:04:54 +00004460 xmlXPathObjectPtr obj1,obj2;
4461
4462 CHECK_TYPE(XPATH_NODESET);
4463 obj1 = valuePop(ctxt);
4464 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004465
Daniel Veillard00fdf371999-10-08 09:40:39 +00004466 NEXT;
4467 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004468 xmlXPathEvalPathExpr(ctxt);
4469
Daniel Veillard740abf52000-10-02 23:04:54 +00004470 CHECK_TYPE(XPATH_NODESET);
4471 obj2 = valuePop(ctxt);
4472 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
4473 obj2->nodesetval);
4474 xmlXPathFreeObject(obj2);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004475 }
4476}
4477
4478/**
4479 * xmlXPathEvalUnaryExpr:
4480 * @ctxt: the XPath Parser context
4481 *
4482 * [27] UnaryExpr ::= UnionExpr
4483 * | '-' UnaryExpr
4484 *
4485 * Parse and evaluate an unary expression, then push the result on the stack
4486 */
4487
4488void
4489xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
4490 int minus = 0;
4491
Daniel Veillard00fdf371999-10-08 09:40:39 +00004492 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004493 if (CUR == '-') {
4494 minus = 1;
4495 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004496 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004497 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004498 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004499 CHECK_ERROR;
4500 if (minus) {
4501 xmlXPathValueFlipSign(ctxt);
4502 }
4503}
4504
4505/**
4506 * xmlXPathEvalMultiplicativeExpr:
4507 * @ctxt: the XPath Parser context
4508 *
4509 * [26] MultiplicativeExpr ::= UnaryExpr
4510 * | MultiplicativeExpr MultiplyOperator UnaryExpr
4511 * | MultiplicativeExpr 'div' UnaryExpr
4512 * | MultiplicativeExpr 'mod' UnaryExpr
4513 * [34] MultiplyOperator ::= '*'
4514 *
4515 * Parse and evaluate an Additive expression, then push the result on the stack
4516 */
4517
4518void
4519xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
4520 xmlXPathEvalUnaryExpr(ctxt);
4521 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004522 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004523 while ((CUR == '*') ||
4524 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
4525 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
4526 int op = -1;
4527
4528 if (CUR == '*') {
4529 op = 0;
4530 NEXT;
4531 } else if (CUR == 'd') {
4532 op = 1;
4533 SKIP(3);
4534 } else if (CUR == 'm') {
4535 op = 2;
4536 SKIP(3);
4537 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004538 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004539 xmlXPathEvalUnaryExpr(ctxt);
4540 CHECK_ERROR;
4541 switch (op) {
4542 case 0:
4543 xmlXPathMultValues(ctxt);
4544 break;
4545 case 1:
4546 xmlXPathDivValues(ctxt);
4547 break;
4548 case 2:
4549 xmlXPathModValues(ctxt);
4550 break;
4551 }
4552 }
4553}
4554
4555/**
4556 * xmlXPathEvalAdditiveExpr:
4557 * @ctxt: the XPath Parser context
4558 *
4559 * [25] AdditiveExpr ::= MultiplicativeExpr
4560 * | AdditiveExpr '+' MultiplicativeExpr
4561 * | AdditiveExpr '-' MultiplicativeExpr
4562 *
4563 * Parse and evaluate an Additive expression, then push the result on the stack
4564 */
4565
4566void
4567xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
4568 xmlXPathEvalMultiplicativeExpr(ctxt);
4569 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004570 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004571 while ((CUR == '+') || (CUR == '-')) {
4572 int plus;
4573
4574 if (CUR == '+') plus = 1;
4575 else plus = 0;
4576 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004577 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004578 xmlXPathEvalMultiplicativeExpr(ctxt);
4579 CHECK_ERROR;
4580 if (plus) xmlXPathAddValues(ctxt);
4581 else xmlXPathSubValues(ctxt);
4582 }
4583}
4584
4585/**
4586 * xmlXPathEvalRelationalExpr:
4587 * @ctxt: the XPath Parser context
4588 *
4589 * [24] RelationalExpr ::= AdditiveExpr
4590 * | RelationalExpr '<' AdditiveExpr
4591 * | RelationalExpr '>' AdditiveExpr
4592 * | RelationalExpr '<=' AdditiveExpr
4593 * | RelationalExpr '>=' AdditiveExpr
4594 *
4595 * A <= B > C is allowed ? Answer from James, yes with
4596 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
4597 * which is basically what got implemented.
4598 *
4599 * Parse and evaluate a Relational expression, then push the result
4600 * on the stack
4601 */
4602
4603void
4604xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
4605 xmlXPathEvalAdditiveExpr(ctxt);
4606 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004607 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004608 while ((CUR == '<') ||
4609 (CUR == '>') ||
4610 ((CUR == '<') && (NXT(1) == '=')) ||
4611 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004612 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004613
4614 if (CUR == '<') inf = 1;
4615 else inf = 0;
4616 if (NXT(1) == '=') strict = 0;
4617 else strict = 1;
4618 NEXT;
4619 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004620 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004621 xmlXPathEvalAdditiveExpr(ctxt);
4622 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004623 ret = xmlXPathCompareValues(ctxt, inf, strict);
4624 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004625 }
4626}
4627
4628/**
4629 * xmlXPathEvalEqualityExpr:
4630 * @ctxt: the XPath Parser context
4631 *
4632 * [23] EqualityExpr ::= RelationalExpr
4633 * | EqualityExpr '=' RelationalExpr
4634 * | EqualityExpr '!=' RelationalExpr
4635 *
4636 * A != B != C is allowed ? Answer from James, yes with
4637 * (RelationalExpr = RelationalExpr) = RelationalExpr
4638 * (RelationalExpr != RelationalExpr) != RelationalExpr
4639 * which is basically what got implemented.
4640 *
4641 * Parse and evaluate an Equality expression, then push the result on the stack
4642 *
4643 */
4644void
4645xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
4646 xmlXPathEvalRelationalExpr(ctxt);
4647 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004648 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004649 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004650 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004651 int eq, equal;
4652
4653 if (CUR == '=') eq = 1;
4654 else eq = 0;
4655 NEXT;
4656 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004657 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004658 xmlXPathEvalRelationalExpr(ctxt);
4659 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004660 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004661 if (eq) res = xmlXPathNewBoolean(equal);
4662 else res = xmlXPathNewBoolean(!equal);
4663 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004664 }
4665}
4666
4667/**
4668 * xmlXPathEvalAndExpr:
4669 * @ctxt: the XPath Parser context
4670 *
4671 * [22] AndExpr ::= EqualityExpr
4672 * | AndExpr 'and' EqualityExpr
4673 *
4674 * Parse and evaluate an AND expression, then push the result on the stack
4675 *
4676 */
4677void
4678xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
4679 xmlXPathEvalEqualityExpr(ctxt);
4680 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004681 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00004682 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004683 xmlXPathObjectPtr arg1, arg2;
4684
4685 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004686 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004687 xmlXPathEvalEqualityExpr(ctxt);
4688 CHECK_ERROR;
4689 arg2 = valuePop(ctxt);
4690 arg1 = valuePop(ctxt);
4691 arg1->boolval &= arg2->boolval;
4692 valuePush(ctxt, arg1);
4693 xmlXPathFreeObject(arg2);
4694 }
4695}
4696
4697/**
4698 * xmlXPathEvalExpr:
4699 * @ctxt: the XPath Parser context
4700 *
4701 * [14] Expr ::= OrExpr
4702 * [21] OrExpr ::= AndExpr
4703 * | OrExpr 'or' AndExpr
4704 *
4705 * Parse and evaluate an expression, then push the result on the stack
4706 *
4707 */
4708void
4709xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
4710 xmlXPathEvalAndExpr(ctxt);
4711 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004712 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004713 while ((CUR == 'o') && (NXT(1) == 'r')) {
4714 xmlXPathObjectPtr arg1, arg2;
4715
4716 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004717 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004718 xmlXPathEvalAndExpr(ctxt);
4719 CHECK_ERROR;
4720 arg2 = valuePop(ctxt);
4721 arg1 = valuePop(ctxt);
4722 arg1->boolval |= arg2->boolval;
4723 valuePush(ctxt, arg1);
4724 xmlXPathFreeObject(arg2);
4725 }
4726}
4727
4728/**
4729 * xmlXPathEvaluatePredicateResult:
4730 * @ctxt: the XPath Parser context
4731 * @res: the Predicate Expression evaluation result
4732 * @index: index of the current node in the current list
4733 *
4734 * Evaluate a predicate result for the current node.
4735 * A PredicateExpr is evaluated by evaluating the Expr and converting
4736 * the result to a boolean. If the result is a number, the result will
4737 * be converted to true if the number is equal to the position of the
4738 * context node in the context node list (as returned by the position
4739 * function) and will be converted to false otherwise; if the result
4740 * is not a number, then the result will be converted as if by a call
4741 * to the boolean function.
4742 */
4743int
4744xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004745 xmlXPathObjectPtr res) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004746 if (res == NULL) return(0);
4747 switch (res->type) {
4748 case XPATH_BOOLEAN:
4749 return(res->boolval);
4750 case XPATH_NUMBER:
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004751 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004752 case XPATH_NODESET:
4753 return(res->nodesetval->nodeNr != 0);
4754 case XPATH_STRING:
4755 return((res->stringval != NULL) &&
4756 (xmlStrlen(res->stringval) != 0));
4757 default:
4758 STRANGE
4759 }
4760 return(0);
4761}
4762
4763/**
4764 * xmlXPathEvalPredicate:
4765 * @ctxt: the XPath Parser context
4766 *
4767 * [8] Predicate ::= '[' PredicateExpr ']'
4768 * [9] PredicateExpr ::= Expr
4769 *
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004770 * ---------------------
4771 * For each node in the node-set to be filtered, the PredicateExpr is
4772 * evaluated with that node as the context node, with the number of nodes
4773 * in the node-set as the context size, and with the proximity position
4774 * of the node in the node-set with respect to the axis as the context
4775 * position; if PredicateExpr evaluates to true for that node, the node
4776 * is included in the new node-set; otherwise, it is not included.
4777 * ---------------------
4778 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004779 * Parse and evaluate a predicate for all the elements of the
4780 * current node list. Then refine the list by removing all
4781 * nodes where the predicate is false.
4782 */
4783void
4784xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004785 const xmlChar *cur;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004786 xmlXPathObjectPtr res;
Daniel Veillard740abf52000-10-02 23:04:54 +00004787 xmlXPathObjectPtr obj, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004788 xmlNodeSetPtr newset = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004789 xmlNodeSetPtr oldset;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004790 int i;
4791
Daniel Veillard00fdf371999-10-08 09:40:39 +00004792 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004793 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004794 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004795 }
4796 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004797 SKIP_BLANKS;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004798
4799 /*
4800 * Extract the old set, and then evaluate the result of the
4801 * expression for all the element in the set. use it to grow
4802 * up a new set.
4803 */
Daniel Veillard740abf52000-10-02 23:04:54 +00004804 CHECK_TYPE(XPATH_NODESET);
4805 obj = valuePop(ctxt);
4806 oldset = obj->nodesetval;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004807 ctxt->context->node = NULL;
4808
4809 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004810 xmlXPathEvalExpr(ctxt);
4811 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004812 ctxt->context->contextSize = 0;
4813 ctxt->context->proximityPosition = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004814 res = valuePop(ctxt);
4815 if (res != NULL)
4816 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00004817 valuePush(ctxt, obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004818 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004819 /*
4820 * Save the expression pointer since we will have to evaluate
4821 * it multiple times. Initialize the new set.
4822 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004823 cur = ctxt->cur;
4824 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00004825
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004826 for (i = 0; i < oldset->nodeNr; i++) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004827 ctxt->cur = cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00004828
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004829 /*
4830 * Run the evaluation with a node list made of a single item
4831 * in the nodeset.
4832 */
4833 ctxt->context->node = oldset->nodeTab[i];
Daniel Veillard740abf52000-10-02 23:04:54 +00004834 tmp = xmlXPathNewNodeSet(ctxt->context->node);
4835 valuePush(ctxt, tmp);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004836 ctxt->context->contextSize = oldset->nodeNr;
4837 ctxt->context->proximityPosition = i + 1;
Daniel Veillardbe803962000-06-28 23:40:59 +00004838
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004839 xmlXPathEvalExpr(ctxt);
4840 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004841
4842 /*
4843 * The result of the evaluation need to be tested to
4844 * decided whether the filter succeeded or not
4845 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004846 res = valuePop(ctxt);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004847 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
4848 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
4849 }
Daniel Veillard740abf52000-10-02 23:04:54 +00004850
4851 /*
4852 * Cleanup
4853 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004854 if (res != NULL)
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004855 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00004856 if (ctxt->value == tmp) {
4857 res = valuePop(ctxt);
4858 xmlXPathFreeObject(res);
4859 }
Daniel Veillardbe803962000-06-28 23:40:59 +00004860
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004861 ctxt->context->node = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004862 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004863
4864 /*
4865 * The result is used as the new evaluation set.
4866 */
Daniel Veillard740abf52000-10-02 23:04:54 +00004867 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004868 ctxt->context->node = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004869 ctxt->context->contextSize = -1;
4870 ctxt->context->proximityPosition = -1;
Daniel Veillard740abf52000-10-02 23:04:54 +00004871 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004872 }
4873 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004874 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004875 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004876
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004877 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004878 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004879#ifdef DEBUG_STEP
4880 fprintf(xmlXPathDebug, "After predicate : ");
Daniel Veillard740abf52000-10-02 23:04:54 +00004881 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004882#endif
4883}
4884
4885/**
4886 * xmlXPathEvalBasis:
4887 * @ctxt: the XPath Parser context
4888 *
4889 * [5] Basis ::= AxisName '::' NodeTest
4890 * | AbbreviatedBasis
4891 * [13] AbbreviatedBasis ::= NodeTest
4892 * | '@' NodeTest
4893 * [7] NodeTest ::= WildcardName
4894 * | NodeType '(' ')'
4895 * | 'processing-instruction' '(' Literal ')'
4896 * [37] WildcardName ::= '*'
4897 * | NCName ':' '*'
4898 * | QName
4899 *
4900 * Evaluate one step in a Location Path
4901 */
4902void
4903xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004904 xmlChar *name = NULL;
4905 xmlChar *prefix = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00004906 xmlXPathTypeVal type = 0;
4907 xmlXPathAxisVal axis = AXIS_CHILD; /* the default on abbreviated syntax */
4908 xmlXPathTestVal nodetest = NODE_TEST_NONE;
4909 xmlElementType nodetype = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004910
4911 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004912 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004913 axis = AXIS_ATTRIBUTE;
4914 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004915 } else if (CUR == '*') {
4916 NEXT;
4917 nodetest = NODE_TEST_ALL;
4918 } else {
4919 name = xmlXPathParseNCName(ctxt);
4920 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004921 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004922 }
4923 type = xmlXPathGetNameType(ctxt, name);
4924 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004925 case IS_FUNCTION: {
4926 xmlXPathFunction func;
4927 int nbargs = 0;
4928 xmlXPathObjectPtr top;
4929
4930 top = ctxt->value;
4931 func = xmlXPathIsFunction(ctxt, name);
4932 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004933 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004934 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004935 }
4936#ifdef DEBUG_EXPR
4937 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4938#endif
4939
4940 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004941 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004942 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004943 }
4944 NEXT;
4945
4946 while (CUR != ')') {
4947 xmlXPathEvalExpr(ctxt);
4948 nbargs++;
4949 if (CUR == ')') break;
4950 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004951 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004952 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004953 }
4954 NEXT;
4955 }
4956 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004957 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004958 func(ctxt, nbargs);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004959 return;
4960 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004961 /*
4962 * Simple case: no axis seach all given node types.
4963 */
4964 case NODE_TYPE_COMMENT:
4965 if ((CUR != '(') || (NXT(1) != ')')) break;
4966 SKIP(2);
4967 nodetest = NODE_TEST_TYPE;
4968 nodetype = XML_COMMENT_NODE;
4969 goto search_nodes;
4970 case NODE_TYPE_TEXT:
4971 if ((CUR != '(') || (NXT(1) != ')')) break;
4972 SKIP(2);
4973 nodetest = NODE_TEST_TYPE;
4974 nodetype = XML_TEXT_NODE;
4975 goto search_nodes;
4976 case NODE_TYPE_NODE:
4977 if ((CUR != '(') || (NXT(1) != ')')) {
4978 nodetest = NODE_TEST_NAME;
4979 break;
4980 }
4981 SKIP(2);
4982 nodetest = NODE_TEST_TYPE;
4983 nodetype = XML_ELEMENT_NODE;
4984 goto search_nodes;
4985 case NODE_TYPE_PI:
4986 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004987 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004988 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004989 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004990 xmlXPathObjectPtr cur;
4991
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004992 /*
4993 * Specific case: search a PI by name.
4994 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004995 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004996 nodetest = NODE_TEST_PI;
4997 xmlXPathEvalLiteral(ctxt);
4998 CHECK_ERROR;
4999 if (CUR != ')')
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005000 XP_ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00005001 NEXT;
5002 xmlXPathStringFunction(ctxt, 1);
5003 CHECK_ERROR;
5004 cur = valuePop(ctxt);
5005 name = xmlStrdup(cur->stringval);
5006 xmlXPathFreeObject(cur);
5007 } else
5008 SKIP(2);
5009 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005010 goto search_nodes;
5011
5012 /*
5013 * Handling of the compund form: got the axis.
5014 */
5015 case AXIS_ANCESTOR:
5016 case AXIS_ANCESTOR_OR_SELF:
5017 case AXIS_ATTRIBUTE:
5018 case AXIS_CHILD:
5019 case AXIS_DESCENDANT:
5020 case AXIS_DESCENDANT_OR_SELF:
5021 case AXIS_FOLLOWING:
5022 case AXIS_FOLLOWING_SIBLING:
5023 case AXIS_NAMESPACE:
5024 case AXIS_PARENT:
5025 case AXIS_PRECEDING:
5026 case AXIS_PRECEDING_SIBLING:
5027 case AXIS_SELF:
5028 if ((CUR != ':') || (NXT(1) != ':')) {
5029 nodetest = NODE_TEST_NAME;
5030 break;
5031 }
5032 SKIP(2);
5033 axis = type;
5034 break;
5035
5036 /*
5037 * Default: abbreviated syntax the axis is AXIS_CHILD
5038 */
5039 default:
5040 nodetest = NODE_TEST_NAME;
5041 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005042parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005043 if (nodetest == NODE_TEST_NONE) {
5044 if (CUR == '*') {
5045 NEXT;
5046 nodetest = NODE_TEST_ALL;
5047 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005048 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00005049 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005050 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005051 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005052 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005053 }
5054 type = xmlXPathGetNameType(ctxt, name);
5055 switch (type) {
5056 /*
5057 * Simple case: no axis seach all given node types.
5058 */
5059 case NODE_TYPE_COMMENT:
5060 if ((CUR != '(') || (NXT(1) != ')')) break;
5061 SKIP(2);
5062 nodetest = NODE_TEST_TYPE;
5063 nodetype = XML_COMMENT_NODE;
5064 goto search_nodes;
5065 case NODE_TYPE_TEXT:
5066 if ((CUR != '(') || (NXT(1) != ')')) break;
5067 SKIP(2);
5068 nodetest = NODE_TEST_TYPE;
5069 nodetype = XML_TEXT_NODE;
5070 goto search_nodes;
5071 case NODE_TYPE_NODE:
5072 if ((CUR != '(') || (NXT(1) != ')')) {
5073 nodetest = NODE_TEST_NAME;
5074 break;
5075 }
5076 SKIP(2);
5077 nodetest = NODE_TEST_TYPE;
5078 nodetype = XML_ELEMENT_NODE;
5079 goto search_nodes;
5080 case NODE_TYPE_PI:
5081 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00005082 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00005083 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005084 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00005085 xmlXPathObjectPtr cur;
5086
Daniel Veillardb05deb71999-08-10 19:04:08 +00005087 /*
5088 * Specific case: search a PI by name.
5089 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00005090 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005091 nodetest = NODE_TEST_PI;
5092 xmlXPathEvalLiteral(ctxt);
5093 CHECK_ERROR;
5094 if (CUR != ')')
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005095 XP_ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00005096 NEXT;
5097 xmlXPathStringFunction(ctxt, 1);
5098 CHECK_ERROR;
5099 cur = valuePop(ctxt);
5100 name = xmlStrdup(cur->stringval);
5101 xmlXPathFreeObject(cur);
5102 } else
5103 SKIP(2);
5104 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005105 goto search_nodes;
5106 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005107 nodetest = NODE_TEST_NAME;
5108 }
5109 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
5110 NEXT;
5111 prefix = name;
5112 if (CUR == '*') {
5113 NEXT;
5114 nodetest = NODE_TEST_ALL;
5115 } else
5116 name = xmlXPathParseNCName(ctxt);
5117 } else if (name == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005118 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005119 }
5120
5121search_nodes:
5122
5123#ifdef DEBUG_STEP
5124 fprintf(xmlXPathDebug, "Basis : computing new set\n");
5125#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00005126 xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005127 prefix, name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005128#ifdef DEBUG_STEP
5129 fprintf(xmlXPathDebug, "Basis : ");
Daniel Veillard740abf52000-10-02 23:04:54 +00005130 xmlXPathDebugNodeSet(stdout, ctxt->context->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005131#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00005132 if (name != NULL) xmlFree(name);
5133 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005134}
5135
5136/**
5137 * xmlXPathEvalStep:
5138 * @ctxt: the XPath Parser context
5139 *
Daniel Veillardac260302000-10-04 13:33:43 +00005140 * TODO [4] was changed between the WD and the REC
5141 *
5142 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005143 * | AbbreviatedStep
Daniel Veillardac260302000-10-04 13:33:43 +00005144 * [12] AbbreviatedStep ::= '.' | '..'
5145 *
5146 * Modified for XPtr range support as:
5147 *
5148 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5149 * | AbbreviatedStep
5150 * | 'range-to' '(' Expr ')' Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005151 *
5152 * Evaluate one step in a Location Path
5153 * A location step of . is short for self::node(). This is
5154 * particularly useful in conjunction with //. For example, the
5155 * location path .//para is short for
5156 * self::node()/descendant-or-self::node()/child::para
5157 * and so will select all para descendant elements of the context
5158 * node.
5159 * Similarly, a location step of .. is short for parent::node().
5160 * For example, ../title is short for parent::node()/child::title
5161 * and so will select the title children of the parent of the context
5162 * node.
5163 */
5164void
5165xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005166 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005167 if ((CUR == '.') && (NXT(1) == '.')) {
5168 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005169 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005170 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005171 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005172 } else if (CUR == '.') {
5173 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005174 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005175 } else {
Daniel Veillardac260302000-10-04 13:33:43 +00005176#ifdef LIBXML_XPTR_ENABLED
5177 if ((CUR == 'r') && (NXT(1) == 'a') && (NXT(2) == 'n') &&
5178 (NXT(3) == 'g') && (NXT(4) == 'e') && (NXT(5) == '-') &&
5179 (NXT(6) == 't') && (NXT(7) == 'o')) {
5180 xmlXPathObjectPtr range;
5181 const xmlChar *cur;
5182 xmlXPathObjectPtr res, obj;
5183 xmlXPathObjectPtr tmp;
5184 xmlRangeSetPtr newset = NULL;
5185 xmlNodeSetPtr oldset;
5186 int i;
5187
5188 CHECK_TYPE(XPATH_NODESET);
5189 obj = valuePop(ctxt);
5190 oldset = obj->nodesetval;
5191 ctxt->context->node = NULL;
5192
5193 SKIP(8);
5194 SKIP_BLANKS;
5195 if (CUR != '(') {
5196 XP_ERROR(XPATH_EXPR_ERROR);
5197 }
5198 NEXT;
5199 SKIP_BLANKS;
5200
5201 /*
5202 * Save the expression pointer since we will have to evaluate
5203 * it multiple times. Initialize the new set.
5204 */
5205 cur = ctxt->cur;
5206 newset = xmlXPathRangeSetCreate(NULL);
5207
5208 for (i = 0; i < oldset->nodeNr; i++) {
5209 ctxt->cur = cur;
5210
5211 /*
5212 * Run the evaluation with a node list made of a single item
5213 * in the nodeset.
5214 */
5215 ctxt->context->node = oldset->nodeTab[i];
5216 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5217 valuePush(ctxt, tmp);
5218
5219 xmlXPathEvalExpr(ctxt);
5220 CHECK_ERROR;
5221
5222 /*
5223 * The result of the evaluation need to be tested to
5224 * decided whether the filter succeeded or not
5225 */
5226 res = valuePop(ctxt);
5227 range = xmlXPathNewRangeNodeObject(oldset->nodeTab[0], res);
5228 if (range != NULL) {
5229 xmlXPathRangeSetAdd(newset, range);
5230 }
5231
5232 /*
5233 * Cleanup
5234 */
5235 if (res != NULL)
5236 xmlXPathFreeObject(res);
5237 if (ctxt->value == tmp) {
5238 res = valuePop(ctxt);
5239 xmlXPathFreeObject(res);
5240 }
5241
5242 ctxt->context->node = NULL;
5243 }
5244
5245 /*
5246 * The result is used as the new evaluation set.
5247 */
5248 xmlXPathFreeObject(obj);
5249 ctxt->context->node = NULL;
5250 ctxt->context->contextSize = -1;
5251 ctxt->context->proximityPosition = -1;
5252 valuePush(ctxt, xmlXPathWrapRangeSet(newset));
5253
5254 SKIP_BLANKS;
5255 if (CUR != ')') {
5256 XP_ERROR(XPATH_EXPR_ERROR);
5257 }
5258 NEXT;
5259 SKIP_BLANKS;
5260 } else
5261#endif
5262 {
5263 /*
5264 * TODO cleanup productions/procedures
5265 * Basis is no more an XPath production !
5266 */
5267 xmlXPathEvalBasis(ctxt);
5268 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005269 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005270 while (CUR == '[') {
5271 xmlXPathEvalPredicate(ctxt);
5272 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005273
5274 while (CUR == '@') {
5275 xmlXPathEvalBasis(ctxt);
5276 ctxt->context->node = NULL;
5277 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005278 }
5279#ifdef DEBUG_STEP
5280 fprintf(xmlXPathDebug, "Step : ");
5281 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
5282#endif
5283}
5284
5285/**
5286 * xmlXPathEvalRelativeLocationPath:
5287 * @ctxt: the XPath Parser context
5288 *
5289 * [3] RelativeLocationPath ::= Step
5290 * | RelativeLocationPath '/' Step
5291 * | AbbreviatedRelativeLocationPath
5292 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
5293 *
5294 */
5295void
5296xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005297 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005298 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005299 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005300 while (CUR == '/') {
5301 if ((CUR == '/') && (NXT(1) == '/')) {
5302 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005303 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005304 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005305 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005306 xmlXPathEvalStep(ctxt);
5307 } else if (CUR == '/') {
5308 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005309 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005310 xmlXPathEvalStep(ctxt);
5311 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005312 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005313 }
5314}
5315
5316/**
5317 * xmlXPathEvalLocationPath:
5318 * @ctxt: the XPath Parser context
5319 *
5320 * [1] LocationPath ::= RelativeLocationPath
5321 * | AbsoluteLocationPath
5322 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
5323 * | AbbreviatedAbsoluteLocationPath
5324 * [10] AbbreviatedAbsoluteLocationPath ::=
5325 * '//' RelativeLocationPath
5326 *
5327 * // is short for /descendant-or-self::node()/. For example,
5328 * //para is short for /descendant-or-self::node()/child::para and
5329 * so will select any para element in the document (even a para element
5330 * that is a document element will be selected by //para since the
5331 * document element node is a child of the root node); div//para is
5332 * short for div/descendant-or-self::node()/child::para and so will
5333 * select all para descendants of div children.
5334 */
5335void
5336xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005337 SKIP_BLANKS;
5338 if (CUR != '/') {
5339 xmlXPathEvalRelativeLocationPath(ctxt);
5340 } else {
5341 while (CUR == '/') {
5342 if ((CUR == '/') && (NXT(1) == '/')) {
5343 SKIP(2);
5344 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005345 xmlXPathNodeCollectAndTest(ctxt,
Daniel Veillard00fdf371999-10-08 09:40:39 +00005346 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
5347 XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005348 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005349 } else if (CUR == '/') {
5350 NEXT;
5351 SKIP_BLANKS;
5352 xmlXPathRoot(ctxt);
5353 if (CUR != 0)
5354 xmlXPathEvalRelativeLocationPath(ctxt);
5355 } else {
5356 xmlXPathEvalRelativeLocationPath(ctxt);
5357 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005358 }
5359 }
5360}
5361
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005362/**
5363 * xmlXPathEval:
5364 * @str: the XPath expression
Daniel Veillard740abf52000-10-02 23:04:54 +00005365 * @ctx: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005366 *
5367 * Evaluate the XPath Location Path in the given context.
5368 *
5369 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
5370 * the caller has to free the object.
5371 */
5372xmlXPathObjectPtr
Daniel Veillard740abf52000-10-02 23:04:54 +00005373xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
5374 xmlXPathParserContextPtr ctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005375 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005376 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005377
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005378 xmlXPathInit();
5379
Daniel Veillard740abf52000-10-02 23:04:54 +00005380 CHECK_CONTEXT(ctx)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005381
5382 if (xmlXPathDebug == NULL)
5383 xmlXPathDebug = stderr;
Daniel Veillard740abf52000-10-02 23:04:54 +00005384 ctxt = xmlXPathNewParserContext(str, ctx);
5385 valuePush(ctxt, xmlXPathNewNodeSet(ctx->node));
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005386 if (str[0] == '/')
Daniel Veillard740abf52000-10-02 23:04:54 +00005387 xmlXPathRoot(ctxt);
5388 xmlXPathEvalLocationPath(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005389
Daniel Veillard740abf52000-10-02 23:04:54 +00005390 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
5391 fprintf(xmlXPathDebug,
5392 "xmlXPathEval: evaluation failed to return a node set\n");
5393 } else {
5394 res = valuePop(ctxt);
5395 }
5396
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005397 do {
Daniel Veillard740abf52000-10-02 23:04:54 +00005398 tmp = valuePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005399 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00005400 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005401 stack++;
5402 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005403 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005404 if (stack != 0) {
5405 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
5406 stack);
5407 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005408 if (ctxt->error != XPATH_EXPRESSION_OK) {
5409 xmlXPathFreeObject(res);
5410 res = NULL;
5411 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005412
Daniel Veillard740abf52000-10-02 23:04:54 +00005413 xmlXPathFreeParserContext(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005414 return(res);
5415}
5416
5417/**
Daniel Veillardac260302000-10-04 13:33:43 +00005418 * xmlXPathEvalXPtrExpr:
5419 * @str: the XPointer XPtrExpr expression
5420 * @ctx: the XPointer context
5421 *
5422 * Evaluate the location set corresponding to this expression.
5423 *
5424 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
5425 * the caller has to free the object.
5426 */
5427xmlXPathObjectPtr
5428xmlXPathEvalXPtrExpr(const xmlChar *str, xmlXPathContextPtr ctx) {
5429 xmlXPathParserContextPtr ctxt;
5430 xmlXPathObjectPtr res = NULL, tmp;
5431 int stack = 0;
5432
5433 xmlXPathInit();
5434
5435 CHECK_CONTEXT(ctx)
5436
5437 if (xmlXPathDebug == NULL)
5438 xmlXPathDebug = stderr;
5439 ctxt = xmlXPathNewParserContext(str, ctx);
5440 valuePush(ctxt, xmlXPathNewNodeSet(ctx->node));
5441 if (str[0] == '/')
5442 xmlXPathRoot(ctxt);
5443 xmlXPathEvalExpr(ctxt);
5444
5445 if ((ctxt->value == NULL) ||
5446 ((ctxt->value->type != XPATH_NODESET) &&
5447 (ctxt->value->type != XPATH_LOCATIONSET))) {
5448 fprintf(xmlXPathDebug,
5449 "xmlXPathEval: evaluation failed to return a node set\n");
5450 } else {
5451 res = valuePop(ctxt);
5452 }
5453
5454 do {
5455 tmp = valuePop(ctxt);
5456 if (tmp != NULL) {
5457 xmlXPathFreeObject(tmp);
5458 stack++;
5459 }
5460 } while (tmp != NULL);
5461 if (stack != 0) {
5462 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
5463 stack);
5464 }
5465 if (ctxt->error != XPATH_EXPRESSION_OK) {
5466 xmlXPathFreeObject(res);
5467 res = NULL;
5468 }
5469
5470 xmlXPathFreeParserContext(ctxt);
5471 return(res);
5472}
5473
5474/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005475 * xmlXPathEvalExpression:
5476 * @str: the XPath expression
5477 * @ctxt: the XPath context
5478 *
5479 * Evaluate the XPath expression in the given context.
5480 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00005481 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005482 * the caller has to free the object.
5483 */
5484xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005485xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005486 xmlXPathParserContextPtr pctxt;
5487 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005488 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005489
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005490 xmlXPathInit();
5491
Daniel Veillard740abf52000-10-02 23:04:54 +00005492 CHECK_CONTEXT(ctxt)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005493
5494 if (xmlXPathDebug == NULL)
5495 xmlXPathDebug = stderr;
5496 pctxt = xmlXPathNewParserContext(str, ctxt);
5497 xmlXPathEvalExpr(pctxt);
5498
5499 res = valuePop(pctxt);
5500 do {
5501 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005502 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005503 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005504 stack++;
5505 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005506 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005507 if (stack != 0) {
5508 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
5509 stack);
5510 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005511 xmlXPathFreeParserContext(pctxt);
5512 return(res);
5513}
5514
Daniel Veillard361d8452000-04-03 19:48:13 +00005515#endif /* LIBXML_XPATH_ENABLED */