blob: a0f6a2a686a982100daada79a09df5a16a248a34 [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,
4 * designed to be used by both XSLT and XPointer.
5 *
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 Veillardb05deb71999-08-10 19:04:08 +000016#include <config.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000017#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000018#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000019#endif
20#ifdef HAVE_MATH_H
21#include <float.h>
22#endif
23#ifdef HAVE_IEEEFP_H
24#include <ieeefp.h>
25#endif
26#ifdef HAVE_NAN_H
27#include <nan.h>
28#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +000029#include <stdio.h>
Daniel Veillardb96e6431999-08-29 21:02:19 +000030#include <ctype.h>
Daniel Veillard6454aec1999-09-02 22:04:43 +000031#include "xmlmemory.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000032#include "tree.h"
Daniel Veillardb96e6431999-08-29 21:02:19 +000033#include "valid.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000034#include "xpath.h"
35#include "parserInternals.h"
36
37/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000038 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000039 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000040 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000041double xmlXPathNAN = 0;
42double xmlXPathPINF = 1;
43double xmlXPathMINF = -1;
44
Daniel Veillardb05deb71999-08-10 19:04:08 +000045#ifndef isinf
46#ifndef HAVE_ISINF
47
48#if HAVE_FPCLASS
49
50int isinf(double d) {
51 fpclass_t type = fpclass(d);
52 switch (type) {
53 case FP_NINF:
54 return(-1);
55 case FP_PINF:
56 return(1);
57 default:
58 return(0);
59 }
60 return(0);
61}
62
63#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
64
65#if HAVE_FP_CLASS_H
66#include <fp_class.h>
67#endif
68
69int isinf(double d) {
70#if HAVE_FP_CLASS
71 int fpclass = fp_class(d);
72#else
73 int fpclass = fp_class_d(d);
74#endif
75 if (fpclass == FP_POS_INF)
76 return(1);
77 if (fpclass == FP_NEG_INF)
78 return(-1);
79 return(0);
80}
81
82#elif defined(HAVE_CLASS)
83
84int isinf(double d) {
85 int fpclass = class(d);
86 if (fpclass == FP_PLUS_INF)
87 return(1);
88 if (fpclass == FP_MINUS_INF)
89 return(-1);
90 return(0);
91}
92#elif defined(finite) || defined(HAVE_FINITE)
93int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +000094#elif defined(HUGE_VAL)
95static int isinf(double x)
96{
97 if (x == HUGE_VAL)
98 return(1);
99 if (x == -HUGE_VAL)
100 return(-1);
101 return(0);
102}
103#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000104
105#endif /* ! HAVE_ISINF */
106#endif /* ! defined(isinf) */
107
108#ifndef isnan
109#ifndef HAVE_ISNAN
110
111#ifdef HAVE_ISNAND
112#define isnan(f) isnand(f)
113#endif /* HAVE_iSNAND */
114
115#endif /* ! HAVE_iSNAN */
116#endif /* ! defined(isnan) */
117
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000118/**
119 * xmlXPathInit:
120 *
121 * Initialize the XPath environment
122 */
123void
124xmlXPathInit(void) {
125 static int initialized = 0;
126
127 if (initialized) return;
128
129 xmlXPathNAN = 0;
130 xmlXPathNAN /= 0;
131
132 xmlXPathPINF = 1;
133 xmlXPathPINF /= 0;
134
135 xmlXPathMINF = -1;
136 xmlXPathMINF /= 0;
137
138 initialized = 1;
139}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000140
141/* #define DEBUG */
142/* #define DEBUG_STEP */
143/* #define DEBUG_EXPR */
144
145FILE *xmlXPathDebug = NULL;
146
147#define TODO \
148 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
149 __FILE__, __LINE__);
150
151#define STRANGE \
152 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
153 __FILE__, __LINE__);
154
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000155double xmlXPathStringEvalNumber(const CHAR *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000156void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000157
158/************************************************************************
159 * *
160 * Parser stacks related functions and macros *
161 * *
162 ************************************************************************/
163
164/*
165 * Generic function for accessing stacks in the Parser Context
166 */
167
168#define PUSH_AND_POP(type, name) \
169extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
170 if (ctxt->name##Nr >= ctxt->name##Max) { \
171 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000172 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000173 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
174 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000175 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000176 exit(1); \
177 } \
178 } \
179 ctxt->name##Tab[ctxt->name##Nr] = value; \
180 ctxt->name = value; \
181 return(ctxt->name##Nr++); \
182} \
183extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
184 type ret; \
185 if (ctxt->name##Nr <= 0) return(0); \
186 ctxt->name##Nr--; \
187 if (ctxt->name##Nr > 0) \
188 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
189 else \
190 ctxt->name = NULL; \
191 ret = ctxt->name##Tab[ctxt->name##Nr]; \
192 ctxt->name##Tab[ctxt->name##Nr] = 0; \
193 return(ret); \
194} \
195
196PUSH_AND_POP(xmlXPathObjectPtr, value)
197
198/*
199 * Macros for accessing the content. Those should be used only by the parser,
200 * and not exported.
201 *
202 * Dirty macros, i.e. one need to make assumption on the context to use them
203 *
204 * CUR_PTR return the current pointer to the CHAR to be parsed.
205 * CUR returns the current CHAR value, i.e. a 8 bit value if compiled
206 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
207 * in UNICODE mode. This should be used internally by the parser
208 * only to compare to ASCII values otherwise it would break when
209 * running with UTF-8 encoding.
210 * NXT(n) returns the n'th next CHAR. Same as CUR is should be used only
211 * to compare on ASCII based substring.
212 * SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
213 * strings within the parser.
214 * CURRENT Returns the current char value, with the full decoding of
215 * UTF-8 if we are using this mode. It returns an int.
216 * NEXT Skip to the next character, this does the proper decoding
217 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
218 * It returns the pointer to the current CHAR.
219 */
220
221#define CUR (*ctxt->cur)
222#define SKIP(val) ctxt->cur += (val)
223#define NXT(val) ctxt->cur[(val)]
224#define CUR_PTR ctxt->cur
225
226#define SKIP_BLANKS \
227 while (IS_BLANK(*(ctxt->cur))) NEXT
228
229#ifndef USE_UTF_8
230#define CURRENT (*ctxt->cur)
231#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
232#else
233#endif
234
235/************************************************************************
236 * *
237 * Error handling routines *
238 * *
239 ************************************************************************/
240
241#define XPATH_EXPRESSION_OK 0
242#define XPATH_NUMBER_ERROR 1
243#define XPATH_UNFINISHED_LITERAL_ERROR 2
244#define XPATH_START_LITERAL_ERROR 3
245#define XPATH_VARIABLE_REF_ERROR 4
246#define XPATH_UNDEF_VARIABLE_ERROR 5
247#define XPATH_INVALID_PREDICATE_ERROR 6
248#define XPATH_EXPR_ERROR 7
249#define XPATH_UNCLOSED_ERROR 8
250#define XPATH_UNKNOWN_FUNC_ERROR 9
251#define XPATH_INVALID_OPERAND 10
252#define XPATH_INVALID_TYPE 11
253#define XPATH_INVALID_ARITY 12
254
255const char *xmlXPathErrorMessages[] = {
256 "Ok",
257 "Number encoding",
258 "Unfinished litteral",
259 "Start of litteral",
260 "Expected $ for variable reference",
261 "Undefined variable",
262 "Invalid predicate",
263 "Invalid expression",
264 "Missing closing curly brace",
265 "Unregistered function",
266 "Invalid operand",
267 "Invalid type",
268 "Invalid number of arguments",
269};
270
271/**
272 * xmlXPathError:
273 * @ctxt: the XPath Parser context
274 * @file: the file name
275 * @line: the line number
276 * @no: the error number
277 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000278 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000279 *
280 * Returns the newly created object.
281 */
282void
283xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
284 int line, int no) {
285 int n;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000286 const CHAR *cur;
287 const CHAR *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000288
289 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
290 xmlXPathErrorMessages[no]);
291
292 cur = ctxt->cur;
293 base = ctxt->base;
294 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
295 cur--;
296 }
297 n = 0;
298 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
299 cur--;
300 if ((*cur == '\n') || (*cur == '\r')) cur++;
301 base = cur;
302 n = 0;
303 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
304 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
305 n++;
306 }
307 fprintf(xmlXPathDebug, "\n");
308 cur = ctxt->cur;
309 while ((*cur == '\n') || (*cur == '\r'))
310 cur--;
311 n = 0;
312 while ((cur != base) && (n++ < 80)) {
313 fprintf(xmlXPathDebug, " ");
314 base++;
315 }
316 fprintf(xmlXPathDebug,"^\n");
317}
318
319#define CHECK_ERROR \
320 if (ctxt->error != XPATH_EXPRESSION_OK) return
321
322#define ERROR(X) \
323 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
324 ctxt->error = (X); return; }
325
Daniel Veillard991e63d1999-08-15 23:32:28 +0000326#define ERROR0(X) \
327 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
328 ctxt->error = (X); return(0); }
329
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000330#define CHECK_TYPE(typeval) \
331 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
332 ERROR(XPATH_INVALID_TYPE) \
333
334
335/************************************************************************
336 * *
337 * Routines to handle NodeSets *
338 * *
339 ************************************************************************/
340
341#define XML_NODESET_DEFAULT 10
342/**
343 * xmlXPathNodeSetCreate:
344 * @val: an initial xmlNodePtr, or NULL
345 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000346 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000347 *
348 * Returns the newly created object.
349 */
350xmlNodeSetPtr
351xmlXPathNodeSetCreate(xmlNodePtr val) {
352 xmlNodeSetPtr ret;
353
Daniel Veillard6454aec1999-09-02 22:04:43 +0000354 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000355 if (ret == NULL) {
356 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
357 return(NULL);
358 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000359 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000360 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000361 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000362 sizeof(xmlNodePtr));
363 if (ret->nodeTab == NULL) {
364 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
365 return(NULL);
366 }
367 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000368 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000369 ret->nodeMax = XML_NODESET_DEFAULT;
370 ret->nodeTab[ret->nodeNr++] = val;
371 }
372 return(ret);
373}
374
375/**
376 * xmlXPathNodeSetAdd:
377 * @cur: the initial node set
378 * @val: a new xmlNodePtr
379 *
380 * add a new xmlNodePtr ot an existing NodeSet
381 */
382void
383xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
384 int i;
385
386 if (val == NULL) return;
387
388 /*
389 * check against doublons
390 */
391 for (i = 0;i < cur->nodeNr;i++)
392 if (cur->nodeTab[i] == val) return;
393
394 /*
395 * grow the nodeTab if needed
396 */
397 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000398 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000399 sizeof(xmlNodePtr));
400 if (cur->nodeTab == NULL) {
401 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
402 return;
403 }
404 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000405 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000406 cur->nodeMax = XML_NODESET_DEFAULT;
407 } else if (cur->nodeNr == cur->nodeMax) {
408 xmlNodePtr *temp;
409
410 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000411 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000412 sizeof(xmlNodePtr));
413 if (temp == NULL) {
414 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
415 return;
416 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000417 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000418 }
419 cur->nodeTab[cur->nodeNr++] = val;
420}
421
422/**
423 * xmlXPathNodeSetMerge:
424 * @val1: the first NodeSet
425 * @val2: the second NodeSet
426 *
427 * Merges two nodesets, all nodes from @val2 are added to @val1
428 *
429 * Returns val1 once extended or NULL in case of error.
430 */
431xmlNodeSetPtr
432xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
433 int i;
434
435 if (val1 == NULL) return(NULL);
436 if (val2 == NULL) return(val1);
437
438 /*
439 * !!!!! this can be optimized a lot, knowing that both
440 * val1 and val2 already have unicity of their values.
441 */
442
443 for (i = 0;i < val2->nodeNr;i++)
444 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
445
446 return(val1);
447}
448
449/**
450 * xmlXPathNodeSetDel:
451 * @cur: the initial node set
452 * @val: an xmlNodePtr
453 *
454 * Removes an xmlNodePtr from an existing NodeSet
455 */
456void
457xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
458 int i;
459
460 if (cur == NULL) return;
461 if (val == NULL) return;
462
463 /*
464 * check against doublons
465 */
466 for (i = 0;i < cur->nodeNr;i++)
467 if (cur->nodeTab[i] == val) break;
468
469 if (i >= cur->nodeNr) {
470#ifdef DEBUG
471 fprintf(xmlXPathDebug,
472 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
473 val->name);
474#endif
475 return;
476 }
477 cur->nodeNr--;
478 for (;i < cur->nodeNr;i++)
479 cur->nodeTab[i] = cur->nodeTab[i + 1];
480 cur->nodeTab[cur->nodeNr] = NULL;
481}
482
483/**
484 * xmlXPathNodeSetRemove:
485 * @cur: the initial node set
486 * @val: the index to remove
487 *
488 * Removes an entry from an existing NodeSet list.
489 */
490void
491xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
492 if (cur == NULL) return;
493 if (val >= cur->nodeNr) return;
494 cur->nodeNr--;
495 for (;val < cur->nodeNr;val++)
496 cur->nodeTab[val] = cur->nodeTab[val + 1];
497 cur->nodeTab[cur->nodeNr] = NULL;
498}
499
500/**
501 * xmlXPathFreeNodeSet:
502 * @obj: the xmlNodeSetPtr to free
503 *
504 * Free the NodeSet compound (not the actual nodes !).
505 */
506void
507xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
508 if (obj == NULL) return;
509 if (obj->nodeTab != NULL) {
510#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000511 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000512#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000513 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000514 }
515#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000516 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000517#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000518 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000519}
520
Daniel Veillardb96e6431999-08-29 21:02:19 +0000521#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000522/**
523 * xmlXPathDebugNodeSet:
524 * @output: a FILE * for the output
525 * @obj: the xmlNodeSetPtr to free
526 *
527 * Quick display of a NodeSet
528 */
529void
530xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
531 int i;
532
533 if (output == NULL) output = xmlXPathDebug;
534 if (obj == NULL) {
535 fprintf(output, "NodeSet == NULL !\n");
536 return;
537 }
538 if (obj->nodeNr == 0) {
539 fprintf(output, "NodeSet is empty\n");
540 return;
541 }
542 if (obj->nodeTab == NULL) {
543 fprintf(output, " nodeTab == NULL !\n");
544 return;
545 }
546 for (i = 0; i < obj->nodeNr; i++) {
547 if (obj->nodeTab[i] == NULL) {
548 fprintf(output, " NULL !\n");
549 return;
550 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000551 if (obj->nodeTab[i]->type == XML_DOCUMENT_NODE)
552 fprintf(output, " /");
553 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000554 fprintf(output, " noname!");
555 else fprintf(output, " %s", obj->nodeTab[i]->name);
556 }
557 fprintf(output, "\n");
558}
559#endif
560
561/************************************************************************
562 * *
563 * Routines to handle Variable *
564 * *
565 * UNIMPLEMENTED CURRENTLY *
566 * *
567 ************************************************************************/
568
569/**
570 * xmlXPathVariablelookup:
571 * @ctxt: the XPath Parser context
572 * @prefix: the variable name namespace if any
573 * @name: the variable name
574 *
575 * Search in the Variable array of the context for the given
576 * variable value.
577 *
578 * UNIMPLEMENTED: always return NULL.
579 *
580 * Returns the value or NULL if not found
581 */
582xmlXPathObjectPtr
583xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
584 const CHAR *prefix, const CHAR *name) {
585 return(NULL);
586}
587
588/************************************************************************
589 * *
590 * Routines to handle Values *
591 * *
592 ************************************************************************/
593
594/* Allocations are terrible, one need to optimize all this !!! */
595
596/**
597 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000598 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000599 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000600 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000601 *
602 * Returns the newly created object.
603 */
604xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000605xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000606 xmlXPathObjectPtr ret;
607
Daniel Veillard6454aec1999-09-02 22:04:43 +0000608 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000609 if (ret == NULL) {
610 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
611 return(NULL);
612 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000613 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000614 ret->type = XPATH_NUMBER;
615 ret->floatval = val;
616 return(ret);
617}
618
619/**
620 * xmlXPathNewBoolean:
621 * @val: the boolean value
622 *
623 * Create a new xmlXPathObjectPtr of type boolean and of value @val
624 *
625 * Returns the newly created object.
626 */
627xmlXPathObjectPtr
628xmlXPathNewBoolean(int val) {
629 xmlXPathObjectPtr ret;
630
Daniel Veillard6454aec1999-09-02 22:04:43 +0000631 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000632 if (ret == NULL) {
633 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
634 return(NULL);
635 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000636 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000637 ret->type = XPATH_BOOLEAN;
638 ret->boolval = (val != 0);
639 return(ret);
640}
641
642/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000643 * xmlXPathNewString:
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000644 * @val: the CHAR * value
645 *
646 * Create a new xmlXPathObjectPtr of type string and of value @val
647 *
648 * Returns the newly created object.
649 */
650xmlXPathObjectPtr
651xmlXPathNewString(const CHAR *val) {
652 xmlXPathObjectPtr ret;
653
Daniel Veillard6454aec1999-09-02 22:04:43 +0000654 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000655 if (ret == NULL) {
656 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
657 return(NULL);
658 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000659 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000660 ret->type = XPATH_STRING;
661 ret->stringval = xmlStrdup(val);
662 return(ret);
663}
664
665/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000666 * xmlXPathNewCString:
667 * @val: the char * value
668 *
669 * Create a new xmlXPathObjectPtr of type string and of value @val
670 *
671 * Returns the newly created object.
672 */
673xmlXPathObjectPtr
674xmlXPathNewCString(const char *val) {
675 xmlXPathObjectPtr ret;
676
Daniel Veillard6454aec1999-09-02 22:04:43 +0000677 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000678 if (ret == NULL) {
679 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
680 return(NULL);
681 }
682 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
683 ret->type = XPATH_STRING;
684 ret->stringval = xmlStrdup(BAD_CAST val);
685 return(ret);
686}
687
688/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000689 * xmlXPathNewNodeSet:
690 * @val: the NodePtr value
691 *
692 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
693 * it with the single Node @val
694 *
695 * Returns the newly created object.
696 */
697xmlXPathObjectPtr
698xmlXPathNewNodeSet(xmlNodePtr val) {
699 xmlXPathObjectPtr ret;
700
Daniel Veillard6454aec1999-09-02 22:04:43 +0000701 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000702 if (ret == NULL) {
703 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
704 return(NULL);
705 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000706 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000707 ret->type = XPATH_NODESET;
708 ret->nodesetval = xmlXPathNodeSetCreate(val);
709 return(ret);
710}
711
712/**
713 * xmlXPathNewNodeSetList:
714 * @val: an existing NodeSet
715 *
716 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
717 * it with the Nodeset @val
718 *
719 * Returns the newly created object.
720 */
721xmlXPathObjectPtr
722xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
723 xmlXPathObjectPtr ret;
724
Daniel Veillard6454aec1999-09-02 22:04:43 +0000725 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000726 if (ret == NULL) {
727 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
728 return(NULL);
729 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000730 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000731 ret->type = XPATH_NODESET;
732 ret->nodesetval = val;
733 return(ret);
734}
735
736/**
737 * xmlXPathFreeObject:
738 * @obj: the object to free
739 *
740 * Free up an xmlXPathObjectPtr object.
741 */
742void
743xmlXPathFreeObject(xmlXPathObjectPtr obj) {
744 if (obj == NULL) return;
745 if (obj->nodesetval != NULL)
746 xmlXPathFreeNodeSet(obj->nodesetval);
747 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000748 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000749#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000750 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000751#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000752 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000753}
754
755/************************************************************************
756 * *
757 * Routines to handle XPath contexts *
758 * *
759 ************************************************************************/
760
761/**
762 * xmlXPathNewContext:
763 * @doc: the XML document
764 * @variables: the variable list
765 * @functions: the function list
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000766 *
767 * Create a new xmlXPathContext
768 *
769 * Returns the xmlXPathContext just allocated.
770 */
771xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000772xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000773 xmlXPathContextPtr ret;
774
Daniel Veillard6454aec1999-09-02 22:04:43 +0000775 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000776 if (ret == NULL) {
777 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
778 return(NULL);
779 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000780 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000781 ret->doc = doc;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000782
783 ret->nb_variables = 0;
784 ret->max_variables = 0;
785 ret->variables = NULL;
786
787 ret->nb_types = 0;
788 ret->max_types = 0;
789 ret->types = NULL;
790
791 ret->nb_funcs = 0;
792 ret->max_funcs = 0;
793 ret->funcs = NULL;
794
795 ret->nb_axis = 0;
796 ret->max_axis = 0;
797 ret->axis = NULL;
798
Daniel Veillardb96e6431999-08-29 21:02:19 +0000799 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000800 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000801 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000802 return(ret);
803}
804
805/**
806 * xmlXPathFreeContext:
807 * @ctxt: the context to free
808 *
809 * Free up an xmlXPathContext
810 */
811void
812xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000813 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000814 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000815
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000816#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000817 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000818#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000819 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000820}
821
822/************************************************************************
823 * *
824 * Routines to handle XPath parser contexts *
825 * *
826 ************************************************************************/
827
828#define CHECK_CTXT \
829 if (ctxt == NULL) { \
830 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
831 __FILE__, __LINE__); \
832 } \
833
834
835#define CHECK_CONTEXT \
836 if (ctxt == NULL) { \
837 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
838 __FILE__, __LINE__); \
839 } \
840 if (ctxt->doc == NULL) { \
841 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
842 __FILE__, __LINE__); \
843 } \
844 if (ctxt->doc->root == NULL) { \
845 fprintf(xmlXPathDebug, \
846 "%s:%d Internal error: document without root\n", \
847 __FILE__, __LINE__); \
848 } \
849
850
851/**
852 * xmlXPathNewParserContext:
853 * @str: the XPath expression
854 * @ctxt: the XPath context
855 *
856 * Create a new xmlXPathParserContext
857 *
858 * Returns the xmlXPathParserContext just allocated.
859 */
860xmlXPathParserContextPtr
861xmlXPathNewParserContext(const CHAR *str, xmlXPathContextPtr ctxt) {
862 xmlXPathParserContextPtr ret;
863
Daniel Veillard6454aec1999-09-02 22:04:43 +0000864 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000865 if (ret == NULL) {
866 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
867 return(NULL);
868 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000869 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000870 ret->cur = ret->base = str;
871 ret->context = ctxt;
872
873 /* Allocate the value stack */
874 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000875 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000876 ret->valueNr = 0;
877 ret->valueMax = 10;
878 ret->value = NULL;
879 return(ret);
880}
881
882/**
883 * xmlXPathFreeParserContext:
884 * @ctxt: the context to free
885 *
886 * Free up an xmlXPathParserContext
887 */
888void
889xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
890 if (ctxt->valueTab != NULL) {
891#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000892 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000893#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000894 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000895 }
896#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000897 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000898#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000899 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000900}
901
902/************************************************************************
903 * *
904 * The implicit core function library *
905 * *
906 ************************************************************************/
907
908/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000909 * Auto-pop and cast to a number
910 */
911void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
912
913#define CHECK_ARITY(x) \
914 if (nargs != (x)) { \
915 ERROR(XPATH_INVALID_ARITY); \
916 } \
917
918
919#define POP_FLOAT \
920 arg = valuePop(ctxt); \
921 if (arg == NULL) { \
922 ERROR(XPATH_INVALID_OPERAND); \
923 } \
924 if (arg->type != XPATH_NUMBER) { \
925 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000926 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000927 arg = valuePop(ctxt); \
928 }
929
930/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000931 * xmlXPathEqualNodeSetString
932 * @arg: the nodeset object argument
933 * @str: the string to compare to.
934 *
935 * Implement the equal operation on XPath objects content: @arg1 == @arg2
936 * If one object to be compared is a node-set and the other is a string,
937 * then the comparison will be true if and only if there is a node in
938 * the node-set such that the result of performing the comparison on the
939 * string-value of the node and the other string is true.
940 *
941 * Returns 0 or 1 depending on the results of the test.
942 */
943int
944xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const CHAR *str) {
945 int i;
946 xmlNodeSetPtr ns;
947 CHAR *str2;
948
949 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
950 return(0);
951 ns = arg->nodesetval;
952 for (i = 0;i < ns->nodeNr;i++) {
953 str2 = xmlNodeGetContent(ns->nodeTab[i]);
954 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000955 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000956 return(1);
957 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000958 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000959 }
960 return(0);
961}
962
963/**
964 * xmlXPathEqualNodeSetFloat
965 * @arg: the nodeset object argument
966 * @f: the float to compare to
967 *
968 * Implement the equal operation on XPath objects content: @arg1 == @arg2
969 * If one object to be compared is a node-set and the other is a number,
970 * then the comparison will be true if and only if there is a node in
971 * the node-set such that the result of performing the comparison on the
972 * number to be compared and on the result of converting the string-value
973 * of that node to a number using the number function is true.
974 *
975 * Returns 0 or 1 depending on the results of the test.
976 */
977int
978xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000979 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +0000980
981 if ((arg == NULL) || (arg->type != XPATH_NODESET))
982 return(0);
983
984 if (isnan(f))
985 sprintf(buf, "NaN");
986 else if (isinf(f) > 0)
987 sprintf(buf, "+Infinity");
988 else if (isinf(f) < 0)
989 sprintf(buf, "-Infinity");
990 else
991 sprintf(buf, "%0g", f);
992
Daniel Veillardb96e6431999-08-29 21:02:19 +0000993 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +0000994}
995
996
997/**
998 * xmlXPathEqualNodeSets
999 * @arg1: first nodeset object argument
1000 * @arg2: second nodeset object argument
1001 *
1002 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1003 * If both objects to be compared are node-sets, then the comparison
1004 * will be true if and only if there is a node in the first node-set and
1005 * a node in the second node-set such that the result of performing the
1006 * comparison on the string-values of the two nodes is true.
1007 *
1008 * (needless to say, this is a costly operation)
1009 *
1010 * Returns 0 or 1 depending on the results of the test.
1011 */
1012int
1013xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1014 int i;
1015 xmlNodeSetPtr ns;
1016 CHAR *str;
1017
1018 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1019 return(0);
1020 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1021 return(0);
1022
1023 ns = arg1->nodesetval;
1024 for (i = 0;i < ns->nodeNr;i++) {
1025 str = xmlNodeGetContent(ns->nodeTab[i]);
1026 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001027 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001028 return(1);
1029 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001030 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001031 }
1032 return(0);
1033}
1034
1035/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001036 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001037 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001038 *
1039 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1040 *
1041 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001042 */
1043int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001044xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1045 xmlXPathObjectPtr arg1, arg2;
1046 int ret = 0;
1047
1048 arg1 = valuePop(ctxt);
1049 if (arg1 == NULL)
1050 ERROR0(XPATH_INVALID_OPERAND);
1051
1052 arg2 = valuePop(ctxt);
1053 if (arg2 == NULL) {
1054 xmlXPathFreeObject(arg1);
1055 ERROR0(XPATH_INVALID_OPERAND);
1056 }
1057
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001058 if (arg1 == arg2) {
1059#ifdef DEBUG_EXPR
1060 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1061#endif
1062 return(1);
1063 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001064
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001065 switch (arg1->type) {
1066 case XPATH_UNDEFINED:
1067#ifdef DEBUG_EXPR
1068 fprintf(xmlXPathDebug, "Equal: undefined\n");
1069#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001070 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001071 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001072 switch (arg2->type) {
1073 case XPATH_UNDEFINED:
1074#ifdef DEBUG_EXPR
1075 fprintf(xmlXPathDebug, "Equal: undefined\n");
1076#endif
1077 break;
1078 case XPATH_NODESET:
1079 ret = xmlXPathEqualNodeSets(arg1, arg2);
1080 break;
1081 case XPATH_BOOLEAN:
1082 if ((arg1->nodesetval == NULL) ||
1083 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1084 else
1085 ret = 1;
1086 ret = (ret == arg2->boolval);
1087 break;
1088 case XPATH_NUMBER:
1089 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1090 break;
1091 case XPATH_STRING:
1092 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1093 break;
1094 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001095 break;
1096 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001097 switch (arg2->type) {
1098 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001099#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001100 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001101#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001102 break;
1103 case XPATH_NODESET:
1104 if ((arg2->nodesetval == NULL) ||
1105 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1106 else
1107 ret = 1;
1108 break;
1109 case XPATH_BOOLEAN:
1110#ifdef DEBUG_EXPR
1111 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1112 arg1->boolval, arg2->boolval);
1113#endif
1114 ret = (arg1->boolval == arg2->boolval);
1115 break;
1116 case XPATH_NUMBER:
1117 if (arg2->floatval) ret = 1;
1118 else ret = 0;
1119 ret = (arg1->boolval == ret);
1120 break;
1121 case XPATH_STRING:
1122 if ((arg2->stringval == NULL) ||
1123 (arg2->stringval[0] == 0)) ret = 0;
1124 else
1125 ret = 1;
1126 ret = (arg1->boolval == ret);
1127 break;
1128 }
1129 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001130 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001131 switch (arg2->type) {
1132 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001133#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001134 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001135#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001136 break;
1137 case XPATH_NODESET:
1138 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1139 break;
1140 case XPATH_BOOLEAN:
1141 if (arg1->floatval) ret = 1;
1142 else ret = 0;
1143 ret = (arg2->boolval == ret);
1144 break;
1145 case XPATH_STRING:
1146 valuePush(ctxt, arg2);
1147 xmlXPathNumberFunction(ctxt, 1);
1148 arg2 = valuePop(ctxt);
1149 /* no break on purpose */
1150 case XPATH_NUMBER:
1151 ret = (arg1->floatval == arg2->floatval);
1152 break;
1153 }
1154 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001155 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001156 switch (arg2->type) {
1157 case XPATH_UNDEFINED:
1158#ifdef DEBUG_EXPR
1159 fprintf(xmlXPathDebug, "Equal: undefined\n");
1160#endif
1161 break;
1162 case XPATH_NODESET:
1163 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1164 break;
1165 case XPATH_BOOLEAN:
1166 if ((arg1->stringval == NULL) ||
1167 (arg1->stringval[0] == 0)) ret = 0;
1168 else
1169 ret = 1;
1170 ret = (arg2->boolval == ret);
1171 break;
1172 case XPATH_STRING:
1173 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1174 break;
1175 case XPATH_NUMBER:
1176 valuePush(ctxt, arg1);
1177 xmlXPathNumberFunction(ctxt, 1);
1178 arg1 = valuePop(ctxt);
1179 ret = (arg1->floatval == arg2->floatval);
1180 break;
1181 }
1182 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001183#ifdef DEBUG_EXPR
1184 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
1185 arg1->stringval, arg2->stringval);
1186#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001187 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001188 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001189 xmlXPathFreeObject(arg1);
1190 xmlXPathFreeObject(arg2);
1191 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001192}
1193
1194/**
1195 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001196 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001197 * @inf: less than (1) or greater than (2)
1198 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001199 *
1200 * Implement the compare operation on XPath objects:
1201 * @arg1 < @arg2 (1, 1, ...
1202 * @arg1 <= @arg2 (1, 0, ...
1203 * @arg1 > @arg2 (0, 1, ...
1204 * @arg1 >= @arg2 (0, 0, ...
1205 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001206 * When neither object to be compared is a node-set and the operator is
1207 * <=, <, >=, >, then the objects are compared by converted both objects
1208 * to numbers and comparing the numbers according to IEEE 754. The <
1209 * comparison will be true if and only if the first number is less than the
1210 * second number. The <= comparison will be true if and only if the first
1211 * number is less than or equal to the second number. The > comparison
1212 * will be true if and only if the first number is greater than the second
1213 * number. The >= comparison will be true if and only if the first number
1214 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001215 */
1216int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001217xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1218 int ret = 0;
1219 xmlXPathObjectPtr arg1, arg2;
1220
1221 arg2 = valuePop(ctxt);
1222 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1223 if (arg2 != NULL)
1224 xmlXPathFreeObject(arg2);
1225 ERROR0(XPATH_INVALID_OPERAND);
1226 }
1227
1228 arg1 = valuePop(ctxt);
1229 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1230 if (arg1 != NULL)
1231 xmlXPathFreeObject(arg1);
1232 xmlXPathFreeObject(arg2);
1233 ERROR0(XPATH_INVALID_OPERAND);
1234 }
1235
1236 if (arg1->type != XPATH_NUMBER) {
1237 valuePush(ctxt, arg1);
1238 xmlXPathNumberFunction(ctxt, 1);
1239 arg1 = valuePop(ctxt);
1240 }
1241 if (arg1->type != XPATH_NUMBER) {
1242 xmlXPathFreeObject(arg1);
1243 xmlXPathFreeObject(arg2);
1244 ERROR0(XPATH_INVALID_OPERAND);
1245 }
1246 if (arg2->type != XPATH_NUMBER) {
1247 valuePush(ctxt, arg2);
1248 xmlXPathNumberFunction(ctxt, 1);
1249 arg2 = valuePop(ctxt);
1250 }
1251 if (arg2->type != XPATH_NUMBER) {
1252 xmlXPathFreeObject(arg1);
1253 xmlXPathFreeObject(arg2);
1254 ERROR0(XPATH_INVALID_OPERAND);
1255 }
1256 /*
1257 * Add tests for infinity and nan
1258 * => feedback on 3.4 for Inf and NaN
1259 */
1260 if (inf && strict)
1261 ret = (arg1->floatval < arg2->floatval);
1262 else if (inf && !strict)
1263 ret = (arg1->floatval <= arg2->floatval);
1264 else if (!inf && strict)
1265 ret = (arg1->floatval > arg2->floatval);
1266 else if (!inf && !strict)
1267 ret = (arg1->floatval >= arg2->floatval);
1268 xmlXPathFreeObject(arg1);
1269 xmlXPathFreeObject(arg2);
1270 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001271}
1272
1273/**
1274 * xmlXPathValueFlipSign:
1275 * @ctxt: the XPath Parser context
1276 *
1277 * Implement the unary - operation on an XPath object
1278 * The numeric operators convert their operands to numbers as if
1279 * by calling the number function.
1280 */
1281void
1282xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1283 xmlXPathObjectPtr arg;
1284
1285 POP_FLOAT
1286 arg->floatval = -arg->floatval;
1287 valuePush(ctxt, arg);
1288}
1289
1290/**
1291 * xmlXPathAddValues:
1292 * @ctxt: the XPath Parser context
1293 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001294 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001295 * The numeric operators convert their operands to numbers as if
1296 * by calling the number function.
1297 */
1298void
1299xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1300 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001301 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001302
1303 POP_FLOAT
1304 val = arg->floatval;
1305 xmlXPathFreeObject(arg);
1306
1307 POP_FLOAT
1308 arg->floatval += val;
1309 valuePush(ctxt, arg);
1310}
1311
1312/**
1313 * xmlXPathSubValues:
1314 * @ctxt: the XPath Parser context
1315 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001316 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001317 * The numeric operators convert their operands to numbers as if
1318 * by calling the number function.
1319 */
1320void
1321xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1322 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001323 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001324
1325 POP_FLOAT
1326 val = arg->floatval;
1327 xmlXPathFreeObject(arg);
1328
1329 POP_FLOAT
1330 arg->floatval -= val;
1331 valuePush(ctxt, arg);
1332}
1333
1334/**
1335 * xmlXPathMultValues:
1336 * @ctxt: the XPath Parser context
1337 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001338 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001339 * The numeric operators convert their operands to numbers as if
1340 * by calling the number function.
1341 */
1342void
1343xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1344 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001345 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001346
1347 POP_FLOAT
1348 val = arg->floatval;
1349 xmlXPathFreeObject(arg);
1350
1351 POP_FLOAT
1352 arg->floatval *= val;
1353 valuePush(ctxt, arg);
1354}
1355
1356/**
1357 * xmlXPathDivValues:
1358 * @ctxt: the XPath Parser context
1359 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001360 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001361 * The numeric operators convert their operands to numbers as if
1362 * by calling the number function.
1363 */
1364void
1365xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1366 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001367 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001368
1369 POP_FLOAT
1370 val = arg->floatval;
1371 xmlXPathFreeObject(arg);
1372
1373 POP_FLOAT
1374 arg->floatval /= val;
1375 valuePush(ctxt, arg);
1376}
1377
1378/**
1379 * xmlXPathModValues:
1380 * @ctxt: the XPath Parser context
1381 *
1382 * Implement the div operation on XPath objects: @arg1 / @arg2
1383 * The numeric operators convert their operands to numbers as if
1384 * by calling the number function.
1385 */
1386void
1387xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1388 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001389 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001390
1391 POP_FLOAT
1392 val = arg->floatval;
1393 xmlXPathFreeObject(arg);
1394
1395 POP_FLOAT
1396 arg->floatval /= val;
1397 valuePush(ctxt, arg);
1398}
1399
1400/************************************************************************
1401 * *
1402 * The traversal functions *
1403 * *
1404 ************************************************************************/
1405
1406#define AXIS_ANCESTOR 1
1407#define AXIS_ANCESTOR_OR_SELF 2
1408#define AXIS_ATTRIBUTE 3
1409#define AXIS_CHILD 4
1410#define AXIS_DESCENDANT 5
1411#define AXIS_DESCENDANT_OR_SELF 6
1412#define AXIS_FOLLOWING 7
1413#define AXIS_FOLLOWING_SIBLING 8
1414#define AXIS_NAMESPACE 9
1415#define AXIS_PARENT 10
1416#define AXIS_PRECEDING 11
1417#define AXIS_PRECEDING_SIBLING 12
1418#define AXIS_SELF 13
1419
1420/*
1421 * A traversal function enumerates nodes along an axis.
1422 * Initially it must be called with NULL, and it indicates
1423 * termination on the axis by returning NULL.
1424 */
1425typedef xmlNodePtr (*xmlXPathTraversalFunction)
1426 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1427
1428/**
1429 * mlXPathNextSelf:
1430 * @ctxt: the XPath Parser context
1431 * @cur: the current node in the traversal
1432 *
1433 * Traversal function for the "self" direction
1434 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001435 *
1436 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001437 */
1438xmlNodePtr
1439xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1440 if (cur == NULL)
1441 return(ctxt->context->node);
1442 return(NULL);
1443}
1444
1445/**
1446 * mlXPathNextChild:
1447 * @ctxt: the XPath Parser context
1448 * @cur: the current node in the traversal
1449 *
1450 * Traversal function for the "child" direction
1451 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001452 *
1453 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001454 */
1455xmlNodePtr
1456xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001457 if (cur == NULL) {
1458 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1459 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001460 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001461 }
1462 if (ctxt->context->node->type == XML_DOCUMENT_NODE)
1463 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001464 return(cur->next);
1465}
1466
1467/**
1468 * mlXPathNextDescendant:
1469 * @ctxt: the XPath Parser context
1470 * @cur: the current node in the traversal
1471 *
1472 * Traversal function for the "descendant" direction
1473 * the descendant axis contains the descendants of the context node in document
1474 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001475 *
1476 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001477 */
1478xmlNodePtr
1479xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001480 if (cur == NULL) {
1481 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1482 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001483 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001484 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001485
1486 if (cur->childs != NULL) return(cur->childs);
1487 if (cur->next != NULL) return(cur->next);
1488
1489 do {
1490 cur = cur->parent;
1491 if (cur == NULL) return(NULL);
1492 if (cur == ctxt->context->node) return(NULL);
1493 if (cur->next != NULL) {
1494 cur = cur->next;
1495 return(cur);
1496 }
1497 } while (cur != NULL);
1498 return(cur);
1499}
1500
1501/**
1502 * mlXPathNextDescendantOrSelf:
1503 * @ctxt: the XPath Parser context
1504 * @cur: the current node in the traversal
1505 *
1506 * Traversal function for the "descendant-or-self" direction
1507 * the descendant-or-self axis contains the context node and the descendants
1508 * of the context node in document order; thus the context node is the first
1509 * node on the axis, and the first child of the context node is the second node
1510 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001511 *
1512 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001513 */
1514xmlNodePtr
1515xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1516 if (cur == NULL)
1517 return(ctxt->context->node);
1518
Daniel Veillardb05deb71999-08-10 19:04:08 +00001519 if (cur == (xmlNodePtr) ctxt->context->doc)
1520 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001521 if (cur->childs != NULL) return(cur->childs);
1522 if (cur->next != NULL) return(cur->next);
1523
1524 do {
1525 cur = cur->parent;
1526 if (cur == NULL) return(NULL);
1527 if (cur == ctxt->context->node) return(NULL);
1528 if (cur->next != NULL) {
1529 cur = cur->next;
1530 return(cur);
1531 }
1532 } while (cur != NULL);
1533 return(cur);
1534}
1535
1536/**
1537 * xmlXPathNextParent:
1538 * @ctxt: the XPath Parser context
1539 * @cur: the current node in the traversal
1540 *
1541 * Traversal function for the "parent" direction
1542 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001543 *
1544 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001545 */
1546xmlNodePtr
1547xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1548 /*
1549 * !!!!!!!!!!!!!
1550 * the parent of an attribute or namespace node is the element
1551 * to which the attribute or namespace node is attached
1552 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001553 if (cur == NULL) {
1554 if (ctxt->context->node->parent == NULL)
1555 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001556 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001557 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001558 return(NULL);
1559}
1560
1561/**
1562 * xmlXPathNextAncestor:
1563 * @ctxt: the XPath Parser context
1564 * @cur: the current node in the traversal
1565 *
1566 * Traversal function for the "ancestor" direction
1567 * the ancestor axis contains the ancestors of the context node; the ancestors
1568 * of the context node consist of the parent of context node and the parent's
1569 * parent and so on; the nodes are ordered in reverse document order; thus the
1570 * parent is the first node on the axis, and the parent's parent is the second
1571 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001572 *
1573 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001574 */
1575xmlNodePtr
1576xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1577 /*
1578 * !!!!!!!!!!!!!
1579 * the parent of an attribute or namespace node is the element
1580 * to which the attribute or namespace node is attached
1581 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001582 if (cur == NULL) {
1583 if (ctxt->context->node->parent == NULL)
1584 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001585 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001586 }
1587 if (cur == ctxt->context->doc->root)
1588 return((xmlNodePtr) ctxt->context->doc);
1589 if (cur == (xmlNodePtr) ctxt->context->doc)
1590 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001591 return(cur->parent);
1592}
1593
1594/**
1595 * xmlXPathNextAncestorOrSelf:
1596 * @ctxt: the XPath Parser context
1597 * @cur: the current node in the traversal
1598 *
1599 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001600 * he ancestor-or-self axis contains the context node and ancestors of
1601 * the context node in reverse document order; thus the context node is
1602 * the first node on the axis, and the context node's parent the second;
1603 * parent here is defined the same as with the parent axis.
1604 *
1605 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001606 */
1607xmlNodePtr
1608xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1609 /*
1610 * !!!!!!!!!!!!!
1611 * the parent of an attribute or namespace node is the element
1612 * to which the attribute or namespace node is attached
1613 */
1614 if (cur == NULL)
1615 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001616 if (cur == ctxt->context->doc->root)
1617 return((xmlNodePtr) ctxt->context->doc);
1618 if (cur == (xmlNodePtr) ctxt->context->doc)
1619 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001620 return(cur->parent);
1621}
1622
1623/**
1624 * xmlXPathNextFollowingSibling:
1625 * @ctxt: the XPath Parser context
1626 * @cur: the current node in the traversal
1627 *
1628 * Traversal function for the "following-sibling" direction
1629 * The following-sibling axis contains the following siblings of the context
1630 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001631 *
1632 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001633 */
1634xmlNodePtr
1635xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001636 if (cur == (xmlNodePtr) ctxt->context->doc)
1637 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001638 if (cur == NULL)
1639 return(ctxt->context->node->next);
1640 return(cur->next);
1641}
1642
1643/**
1644 * xmlXPathNextPrecedingSibling:
1645 * @ctxt: the XPath Parser context
1646 * @cur: the current node in the traversal
1647 *
1648 * Traversal function for the "preceding-sibling" direction
1649 * The preceding-sibling axis contains the preceding siblings of the context
1650 * node in reverse document order; the first preceding sibling is first on the
1651 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001652 *
1653 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001654 */
1655xmlNodePtr
1656xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001657 if (cur == (xmlNodePtr) ctxt->context->doc)
1658 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001659 if (cur == NULL)
1660 return(ctxt->context->node->prev);
1661 return(cur->prev);
1662}
1663
1664/**
1665 * xmlXPathNextFollowing:
1666 * @ctxt: the XPath Parser context
1667 * @cur: the current node in the traversal
1668 *
1669 * Traversal function for the "following" direction
1670 * The following axis contains all nodes in the same document as the context
1671 * node that are after the context node in document order, excluding any
1672 * descendants and excluding attribute nodes and namespace nodes; the nodes
1673 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001674 *
1675 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001676 */
1677xmlNodePtr
1678xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001679 if (cur == (xmlNodePtr) ctxt->context->doc)
1680 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001681 if (cur == NULL)
1682 return(ctxt->context->node->next);; /* !!!!!!!!! */
1683 if (cur->childs != NULL) return(cur->childs);
1684 if (cur->next != NULL) return(cur->next);
1685
1686 do {
1687 cur = cur->parent;
1688 if (cur == NULL) return(NULL);
1689 if (cur == ctxt->context->doc->root) return(NULL);
1690 if (cur->next != NULL) {
1691 cur = cur->next;
1692 return(cur);
1693 }
1694 } while (cur != NULL);
1695 return(cur);
1696}
1697
1698/**
1699 * xmlXPathNextPreceding:
1700 * @ctxt: the XPath Parser context
1701 * @cur: the current node in the traversal
1702 *
1703 * Traversal function for the "preceding" direction
1704 * the preceding axis contains all nodes in the same document as the context
1705 * node that are before the context node in document order, excluding any
1706 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1707 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001708 *
1709 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001710 */
1711xmlNodePtr
1712xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001713 if (cur == (xmlNodePtr) ctxt->context->doc)
1714 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001715 if (cur == NULL)
1716 return(ctxt->context->node->prev); /* !!!!!!!!! */
1717 if (cur->last != NULL) return(cur->last);
1718 if (cur->prev != NULL) return(cur->prev);
1719
1720 do {
1721 cur = cur->parent;
1722 if (cur == NULL) return(NULL);
1723 if (cur == ctxt->context->doc->root) return(NULL);
1724 if (cur->prev != NULL) {
1725 cur = cur->prev;
1726 return(cur);
1727 }
1728 } while (cur != NULL);
1729 return(cur);
1730}
1731
1732/**
1733 * xmlXPathNextNamespace:
1734 * @ctxt: the XPath Parser context
1735 * @cur: the current attribute in the traversal
1736 *
1737 * Traversal function for the "namespace" direction
1738 * the namespace axis contains the namespace nodes of the context node;
1739 * the order of nodes on this axis is implementation-defined; the axis will
1740 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001741 *
1742 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001743 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001744xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001745xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001746 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1747 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001748 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001749 ctxt->context->namespaces =
1750 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1751 if (ctxt->context->namespaces == NULL) return(NULL);
1752 ctxt->context->nsNr = 0;
1753 }
1754 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001755}
1756
1757/**
1758 * xmlXPathNextAttribute:
1759 * @ctxt: the XPath Parser context
1760 * @cur: the current attribute in the traversal
1761 *
1762 * Traversal function for the "attribute" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001763 *
1764 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001765 */
1766xmlAttrPtr
1767xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001768 if (cur == NULL) {
1769 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1770 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001771 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001772 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001773 return(cur->next);
1774}
1775
1776/************************************************************************
1777 * *
1778 * NodeTest Functions *
1779 * *
1780 ************************************************************************/
1781
1782#define NODE_TEST_NONE 0
1783#define NODE_TEST_TYPE 1
1784#define NODE_TEST_PI 2
1785#define NODE_TEST_ALL 3
1786#define NODE_TEST_NS 4
1787#define NODE_TEST_NAME 5
1788
1789#define NODE_TYPE_COMMENT 50
1790#define NODE_TYPE_TEXT 51
1791#define NODE_TYPE_PI 52
1792#define NODE_TYPE_NODE 53
1793
1794#define IS_FUNCTION 200
1795
1796/**
1797 * xmlXPathNodeCollectAndTest:
1798 * @ctxt: the XPath Parser context
1799 * @cur: the current node to test
1800 *
1801 * This is the function implementing a step: based on the current list
1802 * of nodes, it builds up a new list, looking at all nodes under that
1803 * axis and selecting them.
1804 *
1805 * Returns the new NodeSet resulting from the search.
1806 */
1807xmlNodeSetPtr
1808xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
1809 int test, int type, const CHAR *prefix, const CHAR *name) {
1810#ifdef DEBUG_STEP
1811 int n = 0, t = 0;
1812#endif
1813 int i;
1814 xmlNodeSetPtr ret;
1815 xmlXPathTraversalFunction next = NULL;
1816 xmlNodePtr cur = NULL;
1817
1818 if (ctxt->context->nodelist == NULL) {
1819 if (ctxt->context->node == NULL) {
1820 fprintf(xmlXPathDebug,
1821 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1822 __FILE__, __LINE__);
1823 return(NULL);
1824 }
1825 STRANGE
1826 return(NULL);
1827 }
1828#ifdef DEBUG_STEP
1829 fprintf(xmlXPathDebug, "new step : ");
1830#endif
1831 switch (axis) {
1832 case AXIS_ANCESTOR:
1833#ifdef DEBUG_STEP
1834 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1835#endif
1836 next = xmlXPathNextAncestor; break;
1837 case AXIS_ANCESTOR_OR_SELF:
1838#ifdef DEBUG_STEP
1839 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1840#endif
1841 next = xmlXPathNextAncestorOrSelf; break;
1842 case AXIS_ATTRIBUTE:
1843#ifdef DEBUG_STEP
1844 fprintf(xmlXPathDebug, "axis 'attributes' ");
1845#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001846 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001847 break;
1848 case AXIS_CHILD:
1849#ifdef DEBUG_STEP
1850 fprintf(xmlXPathDebug, "axis 'child' ");
1851#endif
1852 next = xmlXPathNextChild; break;
1853 case AXIS_DESCENDANT:
1854#ifdef DEBUG_STEP
1855 fprintf(xmlXPathDebug, "axis 'descendant' ");
1856#endif
1857 next = xmlXPathNextDescendant; break;
1858 case AXIS_DESCENDANT_OR_SELF:
1859#ifdef DEBUG_STEP
1860 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1861#endif
1862 next = xmlXPathNextDescendantOrSelf; break;
1863 case AXIS_FOLLOWING:
1864#ifdef DEBUG_STEP
1865 fprintf(xmlXPathDebug, "axis 'following' ");
1866#endif
1867 next = xmlXPathNextFollowing; break;
1868 case AXIS_FOLLOWING_SIBLING:
1869#ifdef DEBUG_STEP
1870 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1871#endif
1872 next = xmlXPathNextFollowingSibling; break;
1873 case AXIS_NAMESPACE:
1874#ifdef DEBUG_STEP
1875 fprintf(xmlXPathDebug, "axis 'namespace' ");
1876#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001877 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001878 break;
1879 case AXIS_PARENT:
1880#ifdef DEBUG_STEP
1881 fprintf(xmlXPathDebug, "axis 'parent' ");
1882#endif
1883 next = xmlXPathNextParent; break;
1884 case AXIS_PRECEDING:
1885#ifdef DEBUG_STEP
1886 fprintf(xmlXPathDebug, "axis 'preceding' ");
1887#endif
1888 next = xmlXPathNextPreceding; break;
1889 case AXIS_PRECEDING_SIBLING:
1890#ifdef DEBUG_STEP
1891 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1892#endif
1893 next = xmlXPathNextPrecedingSibling; break;
1894 case AXIS_SELF:
1895#ifdef DEBUG_STEP
1896 fprintf(xmlXPathDebug, "axis 'self' ");
1897#endif
1898 next = xmlXPathNextSelf; break;
1899 }
1900 if (next == NULL) return(NULL);
1901 ret = xmlXPathNodeSetCreate(NULL);
1902#ifdef DEBUG_STEP
1903 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1904 ctxt->context->nodelist->nodeNr);
1905 switch (test) {
1906 case NODE_TEST_NONE:
1907 fprintf(xmlXPathDebug, " seaching for none !!!\n");
1908 break;
1909 case NODE_TEST_TYPE:
1910 fprintf(xmlXPathDebug, " seaching for type %d\n", type);
1911 break;
1912 case NODE_TEST_PI:
1913 fprintf(xmlXPathDebug, " seaching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001914 break;
1915 case NODE_TEST_ALL:
1916 fprintf(xmlXPathDebug, " seaching for *\n");
1917 break;
1918 case NODE_TEST_NS:
1919 fprintf(xmlXPathDebug, " seaching for namespace %s\n",
1920 prefix);
1921 break;
1922 case NODE_TEST_NAME:
1923 fprintf(xmlXPathDebug, " seaching for name %s\n", name);
1924 if (prefix != NULL)
1925 fprintf(xmlXPathDebug, " with namespace %s\n",
1926 prefix);
1927 break;
1928 }
1929 fprintf(xmlXPathDebug, "Testing : ");
1930#endif
1931 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1932 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1933
1934 cur = NULL;
1935 do {
1936 cur = next(ctxt, cur);
1937 if (cur == NULL) break;
1938#ifdef DEBUG_STEP
1939 t++;
1940 fprintf(xmlXPathDebug, " %s", cur->name);
1941#endif
1942 switch (test) {
1943 case NODE_TEST_NONE:
1944 STRANGE
1945 return(NULL);
1946 case NODE_TEST_TYPE:
1947 if (cur->type == type) {
1948#ifdef DEBUG_STEP
1949 n++;
1950#endif
1951 xmlXPathNodeSetAdd(ret, cur);
1952 }
1953 break;
1954 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001955 if (cur->type == XML_PI_NODE) {
1956 if ((name != NULL) &&
1957 (xmlStrcmp(name, cur->name)))
1958 break;
1959#ifdef DEBUG_STEP
1960 n++;
1961#endif
1962 xmlXPathNodeSetAdd(ret, cur);
1963 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001964 break;
1965 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001966 if ((cur->type == XML_ELEMENT_NODE) ||
1967 (cur->type == XML_ATTRIBUTE_NODE)) {
1968 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001969#ifdef DEBUG_STEP
1970 n++;
1971#endif
1972 xmlXPathNodeSetAdd(ret, cur);
1973 }
1974 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001975 case NODE_TEST_NS: {
1976 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001977 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001978 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001979 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001980 switch (cur->type) {
1981 case XML_ELEMENT_NODE:
1982 if (!xmlStrcmp(name, cur->name) &&
1983 (((prefix == NULL) ||
1984 ((cur->ns != NULL) &&
1985 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001986#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00001987 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001988#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00001989 xmlXPathNodeSetAdd(ret, cur);
1990 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001991 break;
1992 case XML_ATTRIBUTE_NODE: {
1993 xmlAttrPtr attr = (xmlAttrPtr) cur;
1994 if (!xmlStrcmp(name, attr->name)) {
1995#ifdef DEBUG_STEP
1996 n++;
1997#endif
1998 xmlXPathNodeSetAdd(ret, cur);
1999 }
2000 break;
2001 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002002 default:
2003 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002004 }
2005 break;
2006
2007 }
2008 } while (cur != NULL);
2009 }
2010#ifdef DEBUG_STEP
2011 fprintf(xmlXPathDebug,
2012 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2013#endif
2014 return(ret);
2015}
2016
2017
2018/************************************************************************
2019 * *
2020 * Implicit tree core function library *
2021 * *
2022 ************************************************************************/
2023
2024/**
2025 * xmlXPathRoot:
2026 * @ctxt: the XPath Parser context
2027 *
2028 * Initialize the context to the root of the document
2029 */
2030void
2031xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2032 if (ctxt->context->nodelist != NULL)
2033 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002034 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2035 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002036}
2037
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002038/************************************************************************
2039 * *
2040 * The explicit core function library *
2041 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2042 * *
2043 ************************************************************************/
2044
2045
2046/**
2047 * xmlXPathLastFunction:
2048 * @ctxt: the XPath Parser context
2049 *
2050 * Implement the last() XPath function
2051 * The last function returns the number of nodes in the context node list.
2052 */
2053void
2054xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2055 CHECK_ARITY(0);
2056 if ((ctxt->context->nodelist == NULL) ||
2057 (ctxt->context->node == NULL) ||
2058 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002059 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002060 } else {
2061 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002062 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002063 }
2064}
2065
2066/**
2067 * xmlXPathPositionFunction:
2068 * @ctxt: the XPath Parser context
2069 *
2070 * Implement the position() XPath function
2071 * The position function returns the position of the context node in the
2072 * context node list. The first position is 1, and so the last positionr
2073 * will be equal to last().
2074 */
2075void
2076xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2077 int i;
2078
2079 CHECK_ARITY(0);
2080 if ((ctxt->context->nodelist == NULL) ||
2081 (ctxt->context->node == NULL) ||
2082 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002083 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002084 }
2085 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2086 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002087 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002088 return;
2089 }
2090 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002091 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002092}
2093
2094/**
2095 * xmlXPathCountFunction:
2096 * @ctxt: the XPath Parser context
2097 *
2098 * Implement the count() XPath function
2099 */
2100void
2101xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2102 xmlXPathObjectPtr cur;
2103
2104 CHECK_ARITY(1);
2105 CHECK_TYPE(XPATH_NODESET);
2106 cur = valuePop(ctxt);
2107
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002108 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002109 xmlXPathFreeObject(cur);
2110}
2111
2112/**
2113 * xmlXPathIdFunction:
2114 * @ctxt: the XPath Parser context
2115 *
2116 * Implement the id() XPath function
2117 * The id function selects elements by their unique ID
2118 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2119 * then the result is the union of the result of applying id to the
2120 * string value of each of the nodes in the argument node-set. When the
2121 * argument to id is of any other type, the argument is converted to a
2122 * string as if by a call to the string function; the string is split
2123 * into a whitespace-separated list of tokens (whitespace is any sequence
2124 * of characters matching the production S); the result is a node-set
2125 * containing the elements in the same document as the context node that
2126 * have a unique ID equal to any of the tokens in the list.
2127 */
2128void
2129xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002130 const CHAR *tokens;
2131 const CHAR *cur;
2132 CHAR *ID;
2133 xmlAttrPtr attr;
2134 xmlNodePtr elem = NULL;
2135 xmlXPathObjectPtr ret, obj;
2136
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002137 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002138 obj = valuePop(ctxt);
2139 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2140 if (obj->type == XPATH_NODESET) {
2141 TODO /* ID function in case of NodeSet */
2142 }
2143 if (obj->type != XPATH_STRING) {
2144 valuePush(ctxt, obj);
2145 xmlXPathStringFunction(ctxt, 1);
2146 obj = valuePop(ctxt);
2147 if (obj->type != XPATH_STRING) {
2148 xmlXPathFreeObject(obj);
2149 return;
2150 }
2151 }
2152 tokens = obj->stringval;
2153
2154 ret = xmlXPathNewNodeSet(NULL);
2155 valuePush(ctxt, ret);
2156 if (tokens == NULL) {
2157 xmlXPathFreeObject(obj);
2158 return;
2159 }
2160
2161 cur = tokens;
2162
2163 while (IS_BLANK(*cur)) cur++;
2164 while (*cur != 0) {
2165 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2166 (*cur == '.') || (*cur == '-') ||
2167 (*cur == '_') || (*cur == ':') ||
2168 (IS_COMBINING(*cur)) ||
2169 (IS_EXTENDER(*cur)))
2170 cur++;
2171
2172 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2173
2174 ID = xmlStrndup(tokens, cur - tokens);
2175 attr = xmlGetID(ctxt->context->doc, ID);
2176 if (attr != NULL) {
2177 elem = attr->node;
2178 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2179 }
2180 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002181 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002182
2183 while (IS_BLANK(*cur)) cur++;
2184 tokens = cur;
2185 }
2186 xmlXPathFreeObject(obj);
2187 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002188}
2189
2190/**
2191 * xmlXPathLocalPartFunction:
2192 * @ctxt: the XPath Parser context
2193 *
2194 * Implement the local-part() XPath function
2195 * The local-part function returns a string containing the local part
2196 * of the name of the node in the argument node-set that is first in
2197 * document order. If the node-set is empty or the first node has no
2198 * name, an empty string is returned. If the argument is omitted it
2199 * defaults to the context node.
2200 */
2201void
2202xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2203 xmlXPathObjectPtr cur;
2204
2205 CHECK_ARITY(1);
2206 CHECK_TYPE(XPATH_NODESET);
2207 cur = valuePop(ctxt);
2208
2209 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002210 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002211 } else {
2212 int i = 0; /* Should be first in document order !!!!! */
2213 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2214 }
2215 xmlXPathFreeObject(cur);
2216}
2217
2218/**
2219 * xmlXPathNamespaceFunction:
2220 * @ctxt: the XPath Parser context
2221 *
2222 * Implement the namespace() XPath function
2223 * The namespace function returns a string containing the namespace URI
2224 * of the expanded name of the node in the argument node-set that is
2225 * first in document order. If the node-set is empty, the first node has
2226 * no name, or the expanded name has no namespace URI, an empty string
2227 * is returned. If the argument is omitted it defaults to the context node.
2228 */
2229void
2230xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2231 xmlXPathObjectPtr cur;
2232
Daniel Veillardb96e6431999-08-29 21:02:19 +00002233 if (nargs == 0) {
2234 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2235 nargs = 1;
2236 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002237 CHECK_ARITY(1);
2238 CHECK_TYPE(XPATH_NODESET);
2239 cur = valuePop(ctxt);
2240
2241 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002242 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002243 } else {
2244 int i = 0; /* Should be first in document order !!!!! */
2245
2246 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002247 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002248 else
2249 valuePush(ctxt, xmlXPathNewString(
2250 cur->nodesetval->nodeTab[i]->ns->href));
2251 }
2252 xmlXPathFreeObject(cur);
2253}
2254
2255/**
2256 * xmlXPathNameFunction:
2257 * @ctxt: the XPath Parser context
2258 *
2259 * Implement the name() XPath function
2260 * The name function returns a string containing a QName representing
2261 * the name of the node in the argument node-set that is first in documenti
2262 * order. The QName must represent the name with respect to the namespace
2263 * declarations in effect on the node whose name is being represented.
2264 * Typically, this will be the form in which the name occurred in the XML
2265 * source. This need not be the case if there are namespace declarations
2266 * in effect on the node that associate multiple prefixes with the same
2267 * namespace. However, an implementation may include information about
2268 * the original prefix in its representation of nodes; in this case, an
2269 * implementation can ensure that the returned string is always the same
2270 * as the QName used in the XML source. If the argument it omitted it
2271 * defaults to the context node.
2272 * Libxml keep the original prefix so the "real qualified name" used is
2273 * returned.
2274 */
2275void
2276xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2277 xmlXPathObjectPtr cur;
2278
2279 CHECK_ARITY(1);
2280 CHECK_TYPE(XPATH_NODESET);
2281 cur = valuePop(ctxt);
2282
2283 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002284 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002285 } else {
2286 int i = 0; /* Should be first in document order !!!!! */
2287
2288 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2289 valuePush(ctxt, xmlXPathNewString(
2290 cur->nodesetval->nodeTab[i]->name));
2291
2292 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002293 char name[2000];
2294 sprintf(name, "%s:%s",
2295 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2296 (char *) cur->nodesetval->nodeTab[i]->name);
2297 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002298 }
2299 }
2300 xmlXPathFreeObject(cur);
2301}
2302
2303/**
2304 * xmlXPathStringFunction:
2305 * @ctxt: the XPath Parser context
2306 *
2307 * Implement the string() XPath function
2308 * he string function converts an object to a string as follows:
2309 * - A node-set is converted to a string by returning the value of
2310 * the node in the node-set that is first in document order.
2311 * If the node-set is empty, an empty string is returned.
2312 * - A number is converted to a string as follows
2313 * + NaN is converted to the string NaN
2314 * + positive zero is converted to the string 0
2315 * + negative zero is converted to the string 0
2316 * + positive infinity is converted to the string Infinity
2317 * + negative infinity is converted to the string -Infinity
2318 * + if the number is an integer, the number is represented in
2319 * decimal form as a Number with no decimal point and no leading
2320 * zeros, preceded by a minus sign (-) if the number is negative
2321 * + otherwise, the number is represented in decimal form as a
2322 * Number including a decimal point with at least one digit
2323 * before the decimal point and at least one digit after the
2324 * decimal point, preceded by a minus sign (-) if the number
2325 * is negative; there must be no leading zeros before the decimal
2326 * point apart possibly from the one required digit immediatelyi
2327 * before the decimal point; beyond the one required digit
2328 * after the decimal point there must be as many, but only as
2329 * many, more digits as are needed to uniquely distinguish the
2330 * number from all other IEEE 754 numeric values.
2331 * - The boolean false value is converted to the string false.
2332 * The boolean true value is converted to the string true.
2333 */
2334void
2335xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2336 xmlXPathObjectPtr cur;
2337
2338 CHECK_ARITY(1);
2339 cur = valuePop(ctxt);
2340 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2341 switch (cur->type) {
2342 case XPATH_NODESET:
2343 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002344 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002345 } else {
2346 CHAR *res;
2347 int i = 0; /* Should be first in document order !!!!! */
2348 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2349 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002350 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002351 }
2352 xmlXPathFreeObject(cur);
2353 return;
2354 case XPATH_STRING:
2355 valuePush(ctxt, cur);
2356 return;
2357 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002358 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2359 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002360 xmlXPathFreeObject(cur);
2361 return;
2362 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002363 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002364
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002365 if (isnan(cur->floatval))
2366 sprintf(buf, "NaN");
2367 else if (isinf(cur->floatval) > 0)
2368 sprintf(buf, "+Infinity");
2369 else if (isinf(cur->floatval) < 0)
2370 sprintf(buf, "-Infinity");
2371 else
2372 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002373 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002374 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002375 return;
2376 }
2377 }
2378 STRANGE
2379}
2380
2381/**
2382 * xmlXPathStringLengthFunction:
2383 * @ctxt: the XPath Parser context
2384 *
2385 * Implement the string-length() XPath function
2386 * The string-length returns the number of characters in the string
2387 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2388 * the context node converted to a string, in other words the value
2389 * of the context node.
2390 */
2391void
2392xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2393 xmlXPathObjectPtr cur;
2394
2395 if (nargs == 0) {
2396 if (ctxt->context->node == NULL) {
2397 valuePush(ctxt, xmlXPathNewFloat(0));
2398 } else {
2399 CHAR *content;
2400
2401 content = xmlNodeGetContent(ctxt->context->node);
2402 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002403 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002404 }
2405 return;
2406 }
2407 CHECK_ARITY(1);
2408 CHECK_TYPE(XPATH_STRING);
2409 cur = valuePop(ctxt);
2410 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2411 xmlXPathFreeObject(cur);
2412}
2413
2414/**
2415 * xmlXPathConcatFunction:
2416 * @ctxt: the XPath Parser context
2417 *
2418 * Implement the concat() XPath function
2419 * The concat function returns the concatenation of its arguments.
2420 */
2421void
2422xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2423 xmlXPathObjectPtr cur, new;
2424 CHAR *tmp;
2425
2426 if (nargs < 2) {
2427 CHECK_ARITY(2);
2428 }
2429
2430 cur = valuePop(ctxt);
2431 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2432 xmlXPathFreeObject(cur);
2433 return;
2434 }
2435 nargs--;
2436
2437 while (nargs > 0) {
2438 new = valuePop(ctxt);
2439 if ((new == NULL) || (new->type != XPATH_STRING)) {
2440 xmlXPathFreeObject(new);
2441 xmlXPathFreeObject(cur);
2442 ERROR(XPATH_INVALID_TYPE);
2443 }
2444 tmp = xmlStrcat(new->stringval, cur->stringval);
2445 new->stringval = cur->stringval;
2446 cur->stringval = tmp;
2447
2448 xmlXPathFreeObject(new);
2449 nargs--;
2450 }
2451 valuePush(ctxt, cur);
2452}
2453
2454/**
2455 * xmlXPathContainsFunction:
2456 * @ctxt: the XPath Parser context
2457 *
2458 * Implement the contains() XPath function
2459 * The contains function returns true if the first argument string
2460 * contains the second argument string, and otherwise returns false.
2461 */
2462void
2463xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2464 xmlXPathObjectPtr hay, needle;
2465
2466 CHECK_ARITY(2);
2467 CHECK_TYPE(XPATH_STRING);
2468 needle = valuePop(ctxt);
2469 hay = valuePop(ctxt);
2470 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2471 xmlXPathFreeObject(hay);
2472 xmlXPathFreeObject(needle);
2473 ERROR(XPATH_INVALID_TYPE);
2474 }
2475 if (xmlStrstr(hay->stringval, needle->stringval))
2476 valuePush(ctxt, xmlXPathNewBoolean(1));
2477 else
2478 valuePush(ctxt, xmlXPathNewBoolean(0));
2479 xmlXPathFreeObject(hay);
2480 xmlXPathFreeObject(needle);
2481}
2482
2483/**
2484 * xmlXPathStartsWithFunction:
2485 * @ctxt: the XPath Parser context
2486 *
2487 * Implement the starts-with() XPath function
2488 * The starts-with function returns true if the first argument string
2489 * starts with the second argument string, and otherwise returns false.
2490 */
2491void
2492xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2493 xmlXPathObjectPtr hay, needle;
2494 int n;
2495
2496 CHECK_ARITY(2);
2497 CHECK_TYPE(XPATH_STRING);
2498 needle = valuePop(ctxt);
2499 hay = valuePop(ctxt);
2500 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2501 xmlXPathFreeObject(hay);
2502 xmlXPathFreeObject(needle);
2503 ERROR(XPATH_INVALID_TYPE);
2504 }
2505 n = xmlStrlen(needle->stringval);
2506 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2507 valuePush(ctxt, xmlXPathNewBoolean(0));
2508 else
2509 valuePush(ctxt, xmlXPathNewBoolean(1));
2510 xmlXPathFreeObject(hay);
2511 xmlXPathFreeObject(needle);
2512}
2513
2514/**
2515 * xmlXPathSubstringFunction:
2516 * @ctxt: the XPath Parser context
2517 *
2518 * Implement the substring() XPath function
2519 * The substring function returns the substring of the first argument
2520 * starting at the position specified in the second argument with
2521 * length specified in the third argument. For example,
2522 * substring("12345",2,3) returns "234". If the third argument is not
2523 * specified, it returns the substring starting at the position specified
2524 * in the second argument and continuing to the end of the string. For
2525 * example, substring("12345",2) returns "2345". More precisely, each
2526 * character in the string (see [3.6 Strings]) is considered to have a
2527 * numeric position: the position of the first character is 1, the position
2528 * of the second character is 2 and so on. The returned substring contains
2529 * those characters for which the position of the character is greater than
2530 * or equal to the second argument and, if the third argument is specified,
2531 * less than the sum of the second and third arguments; the comparisons
2532 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2533 * - substring("12345", 1.5, 2.6) returns "234"
2534 * - substring("12345", 0, 3) returns "12"
2535 * - substring("12345", 0 div 0, 3) returns ""
2536 * - substring("12345", 1, 0 div 0) returns ""
2537 * - substring("12345", -42, 1 div 0) returns "12345"
2538 * - substring("12345", -1 div 0, 1 div 0) returns ""
2539 */
2540void
2541xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2542 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002543 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002544 int i, l;
2545 CHAR *ret;
2546
2547 /*
2548 * Conformance needs to be checked !!!!!
2549 */
2550 if (nargs < 2) {
2551 CHECK_ARITY(2);
2552 }
2553 if (nargs > 3) {
2554 CHECK_ARITY(3);
2555 }
2556 if (nargs == 3) {
2557 CHECK_TYPE(XPATH_NUMBER);
2558 len = valuePop(ctxt);
2559 le = len->floatval;
2560 xmlXPathFreeObject(len);
2561 } else {
2562 le = 2000000000;
2563 }
2564 CHECK_TYPE(XPATH_NUMBER);
2565 start = valuePop(ctxt);
2566 in = start->floatval;
2567 xmlXPathFreeObject(start);
2568 CHECK_TYPE(XPATH_STRING);
2569 str = valuePop(ctxt);
2570 le += in;
2571
2572 /* integer index of the first char */
2573 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002574 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002575
2576 /* integer index of the last char */
2577 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002578 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002579
2580 /* back to a zero based len */
2581 i--;
2582 l--;
2583
2584 /* check against the string len */
2585 if (l > 1024) {
2586 l = xmlStrlen(str->stringval);
2587 }
2588 if (i < 0) {
2589 i = 0;
2590 }
2591
2592 /* number of chars to copy */
2593 l -= i;
2594
2595 ret = xmlStrsub(str->stringval, i, l);
2596 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002597 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002598 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002599 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002600 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002601 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002602 xmlXPathFreeObject(str);
2603}
2604
2605/**
2606 * xmlXPathSubstringBeforeFunction:
2607 * @ctxt: the XPath Parser context
2608 *
2609 * Implement the substring-before() XPath function
2610 * The substring-before function returns the substring of the first
2611 * argument string that precedes the first occurrence of the second
2612 * argument string in the first argument string, or the empty string
2613 * if the first argument string does not contain the second argument
2614 * string. For example, substring-before("1999/04/01","/") returns 1999.
2615 */
2616void
2617xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2618 CHECK_ARITY(2);
2619 TODO /* substring before */
2620}
2621
2622/**
2623 * xmlXPathSubstringAfterFunction:
2624 * @ctxt: the XPath Parser context
2625 *
2626 * Implement the substring-after() XPath function
2627 * The substring-after function returns the substring of the first
2628 * argument string that follows the first occurrence of the second
2629 * argument string in the first argument string, or the empty stringi
2630 * if the first argument string does not contain the second argument
2631 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2632 * and substring-after("1999/04/01","19") returns 99/04/01.
2633 */
2634void
2635xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2636 CHECK_ARITY(2);
2637 TODO /* substring after */
2638}
2639
2640/**
2641 * xmlXPathNormalizeFunction:
2642 * @ctxt: the XPath Parser context
2643 *
2644 * Implement the normalize() XPath function
2645 * The normalize function returns the argument string with white
2646 * space normalized by stripping leading and trailing whitespace
2647 * and replacing sequences of whitespace characters by a single
2648 * space. Whitespace characters are the same allowed by the S production
2649 * in XML. If the argument is omitted, it defaults to the context
2650 * node converted to a string, in other words the value of the context node.
2651 */
2652void
2653xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2654 CHECK_ARITY(1);
2655 TODO /* normalize isn't as boring as translate, but pretty much */
2656}
2657
2658/**
2659 * xmlXPathTranslateFunction:
2660 * @ctxt: the XPath Parser context
2661 *
2662 * Implement the translate() XPath function
2663 * The translate function returns the first argument string with
2664 * occurrences of characters in the second argument string replaced
2665 * by the character at the corresponding position in the third argument
2666 * string. For example, translate("bar","abc","ABC") returns the string
2667 * BAr. If there is a character in the second argument string with no
2668 * character at a corresponding position in the third argument string
2669 * (because the second argument string is longer than the third argument
2670 * string), then occurrences of that character in the first argument
2671 * string are removed. For example, translate("--aaa--","abc-","ABC")
2672 * returns "AAA". If a character occurs more than once in second
2673 * argument string, then the first occurrence determines the replacement
2674 * character. If the third argument string is longer than the second
2675 * argument string, then excess characters are ignored.
2676 */
2677void
2678xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2679 CHECK_ARITY(3);
2680 TODO /* translate is boring, waiting for UTF-8 representation too */
2681}
2682
2683/**
2684 * xmlXPathBooleanFunction:
2685 * @ctxt: the XPath Parser context
2686 *
2687 * Implement the boolean() XPath function
2688 * he boolean function converts its argument to a boolean as follows:
2689 * - a number is true if and only if it is neither positive or
2690 * negative zero nor NaN
2691 * - a node-set is true if and only if it is non-empty
2692 * - a string is true if and only if its length is non-zero
2693 */
2694void
2695xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2696 xmlXPathObjectPtr cur;
2697 int res = 0;
2698
2699 CHECK_ARITY(1);
2700 cur = valuePop(ctxt);
2701 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2702 switch (cur->type) {
2703 case XPATH_NODESET:
2704 if ((cur->nodesetval == NULL) ||
2705 (cur->nodesetval->nodeNr == 0)) res = 0;
2706 else
2707 res = 1;
2708 break;
2709 case XPATH_STRING:
2710 if ((cur->stringval == NULL) ||
2711 (cur->stringval[0] == 0)) res = 0;
2712 else
2713 res = 1;
2714 break;
2715 case XPATH_BOOLEAN:
2716 valuePush(ctxt, cur);
2717 return;
2718 case XPATH_NUMBER:
2719 if (cur->floatval) res = 1;
2720 break;
2721 default:
2722 STRANGE
2723 }
2724 xmlXPathFreeObject(cur);
2725 valuePush(ctxt, xmlXPathNewBoolean(res));
2726}
2727
2728/**
2729 * xmlXPathNotFunction:
2730 * @ctxt: the XPath Parser context
2731 *
2732 * Implement the not() XPath function
2733 * The not function returns true if its argument is false,
2734 * and false otherwise.
2735 */
2736void
2737xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2738 CHECK_ARITY(1);
2739 CHECK_TYPE(XPATH_BOOLEAN);
2740 ctxt->value->boolval = ! ctxt->value->boolval;
2741}
2742
2743/**
2744 * xmlXPathTrueFunction:
2745 * @ctxt: the XPath Parser context
2746 *
2747 * Implement the true() XPath function
2748 */
2749void
2750xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2751 CHECK_ARITY(0);
2752 valuePush(ctxt, xmlXPathNewBoolean(1));
2753}
2754
2755/**
2756 * xmlXPathFalseFunction:
2757 * @ctxt: the XPath Parser context
2758 *
2759 * Implement the false() XPath function
2760 */
2761void
2762xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2763 CHECK_ARITY(0);
2764 valuePush(ctxt, xmlXPathNewBoolean(0));
2765}
2766
2767/**
2768 * xmlXPathLangFunction:
2769 * @ctxt: the XPath Parser context
2770 *
2771 * Implement the lang() XPath function
2772 * The lang function returns true or false depending on whether the
2773 * language of the context node as specified by xml:lang attributes
2774 * is the same as or is a sublanguage of the language specified by
2775 * the argument string. The language of the context node is determined
2776 * by the value of the xml:lang attribute on the context node, or, if
2777 * the context node has no xml:lang attribute, by the value of the
2778 * xml:lang attribute on the nearest ancestor of the context node that
2779 * has an xml:lang attribute. If there is no such attribute, then lang
2780 * returns false. If there is such an attribute, then lang returns
2781 * true if the attribute value is equal to the argument ignoring case,
2782 * or if there is some suffix starting with - such that the attribute
2783 * value is equal to the argument ignoring that suffix of the attribute
2784 * value and ignoring case.
2785 */
2786void
2787xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002788 xmlXPathObjectPtr val;
2789 const CHAR *theLang;
2790 const CHAR *lang;
2791 int ret = 0;
2792 int i;
2793
2794 CHECK_ARITY(1);
2795 CHECK_TYPE(XPATH_STRING);
2796 val = valuePop(ctxt);
2797 lang = val->stringval;
2798 theLang = xmlNodeGetLang(ctxt->context->node);
2799 if ((theLang != NULL) && (lang != NULL)) {
2800 for (i = 0;lang[i] != 0;i++)
2801 if (toupper(lang[i]) != toupper(theLang[i]))
2802 goto not_equal;
2803 ret = 1;
2804 }
2805not_equal:
2806 xmlXPathFreeObject(val);
2807 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002808}
2809
2810/**
2811 * xmlXPathNumberFunction:
2812 * @ctxt: the XPath Parser context
2813 *
2814 * Implement the number() XPath function
2815 */
2816void
2817xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2818 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002819 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002820
2821 CHECK_ARITY(1);
2822 cur = valuePop(ctxt);
2823 switch (cur->type) {
2824 case XPATH_NODESET:
2825 valuePush(ctxt, cur);
2826 xmlXPathStringFunction(ctxt, 1);
2827 cur = valuePop(ctxt);
2828 case XPATH_STRING:
2829 res = xmlXPathStringEvalNumber(cur->stringval);
2830 valuePush(ctxt, xmlXPathNewFloat(res));
2831 xmlXPathFreeObject(cur);
2832 return;
2833 case XPATH_BOOLEAN:
2834 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2835 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2836 xmlXPathFreeObject(cur);
2837 return;
2838 case XPATH_NUMBER:
2839 valuePush(ctxt, cur);
2840 return;
2841 }
2842 STRANGE
2843}
2844
2845/**
2846 * xmlXPathSumFunction:
2847 * @ctxt: the XPath Parser context
2848 *
2849 * Implement the sum() XPath function
2850 * The sum function returns the sum of the values of the nodes in
2851 * the argument node-set.
2852 */
2853void
2854xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2855 CHECK_ARITY(1);
2856 TODO /* BUG Sum : don't understand the definition */
2857}
2858
2859/**
2860 * xmlXPathFloorFunction:
2861 * @ctxt: the XPath Parser context
2862 *
2863 * Implement the floor() XPath function
2864 * The floor function returns the largest (closest to positive infinity)
2865 * number that is not greater than the argument and that is an integer.
2866 */
2867void
2868xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2869 CHECK_ARITY(1);
2870 CHECK_TYPE(XPATH_NUMBER);
2871 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002872 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002873}
2874
2875/**
2876 * xmlXPathCeilingFunction:
2877 * @ctxt: the XPath Parser context
2878 *
2879 * Implement the ceiling() XPath function
2880 * The ceiling function returns the smallest (closest to negative infinity)
2881 * number that is not less than the argument and that is an integer.
2882 */
2883void
2884xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002885 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002886
2887 CHECK_ARITY(1);
2888 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002889 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002890 if (f != ctxt->value->floatval)
2891 ctxt->value->floatval = f + 1;
2892}
2893
2894/**
2895 * xmlXPathRoundFunction:
2896 * @ctxt: the XPath Parser context
2897 *
2898 * Implement the round() XPath function
2899 * The round function returns the number that is closest to the
2900 * argument and that is an integer. If there are two such numbers,
2901 * then the one that is even is returned.
2902 */
2903void
2904xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002905 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002906
2907 CHECK_ARITY(1);
2908 CHECK_TYPE(XPATH_NUMBER);
2909 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002910 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002911 if (ctxt->value->floatval < f + 0.5)
2912 ctxt->value->floatval = f;
2913 else if (ctxt->value->floatval == f + 0.5)
2914 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2915 else
2916 ctxt->value->floatval = f + 1;
2917}
2918
2919/************************************************************************
2920 * *
2921 * The Parser *
2922 * *
2923 ************************************************************************/
2924
2925/*
2926 * a couple of forward declarations since we use a recursive call based
2927 * implementation.
2928 */
2929void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2930void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2931void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2932void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2933
2934/**
2935 * xmlXPathParseNCName:
2936 * @ctxt: the XPath Parser context
2937 *
2938 * parse an XML namespace non qualified name.
2939 *
2940 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2941 *
2942 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2943 * CombiningChar | Extender
2944 *
2945 * Returns the namespace name or NULL
2946 */
2947
2948CHAR *
2949xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
2950 const CHAR *q;
2951 CHAR *ret = NULL;
2952
2953 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2954 q = NEXT;
2955
2956 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2957 (CUR == '.') || (CUR == '-') ||
2958 (CUR == '_') ||
2959 (IS_COMBINING(CUR)) ||
2960 (IS_EXTENDER(CUR)))
2961 NEXT;
2962
2963 ret = xmlStrndup(q, CUR_PTR - q);
2964
2965 return(ret);
2966}
2967
2968/**
2969 * xmlXPathParseQName:
2970 * @ctxt: the XPath Parser context
2971 * @prefix: a CHAR **
2972 *
2973 * parse an XML qualified name
2974 *
2975 * [NS 5] QName ::= (Prefix ':')? LocalPart
2976 *
2977 * [NS 6] Prefix ::= NCName
2978 *
2979 * [NS 7] LocalPart ::= NCName
2980 *
2981 * Returns the function returns the local part, and prefix is updated
2982 * to get the Prefix if any.
2983 */
2984
2985CHAR *
2986xmlXPathParseQName(xmlXPathParserContextPtr ctxt, CHAR **prefix) {
2987 CHAR *ret = NULL;
2988
2989 *prefix = NULL;
2990 ret = xmlXPathParseNCName(ctxt);
2991 if (CUR == ':') {
2992 *prefix = ret;
2993 NEXT;
2994 ret = xmlXPathParseNCName(ctxt);
2995 }
2996 return(ret);
2997}
2998
2999/**
3000 * xmlXPathStringEvalNumber:
3001 * @str: A string to scan
3002 *
3003 * [30] Number ::= Digits ('.' Digits)?
3004 * | '.' Digits
3005 * [31] Digits ::= [0-9]+
3006 *
3007 * Parse and evaluate a Number in the string
3008 *
3009 * BUG: "1.' is not valid ... James promised correction
3010 * as Digits ('.' Digits?)?
3011 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003012 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003013 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003014double
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003015xmlXPathStringEvalNumber(const CHAR *str) {
3016 const CHAR *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003017 double ret = 0.0;
3018 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003019 int ok = 0;
3020
3021 while (*cur == ' ') cur++;
3022 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003023 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003024 }
3025 while ((*cur >= '0') && (*cur <= '9')) {
3026 ret = ret * 10 + (*cur - '0');
3027 ok = 1;
3028 cur++;
3029 }
3030 if (*cur == '.') {
3031 cur++;
3032 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003033 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003034 }
3035 while ((*cur >= '0') && (*cur <= '9')) {
3036 mult /= 10;
3037 ret = ret + (*cur - '0') * mult;
3038 cur++;
3039 }
3040 }
3041 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003042 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003043 return(ret);
3044}
3045
3046/**
3047 * xmlXPathEvalNumber:
3048 * @ctxt: the XPath Parser context
3049 *
3050 * [30] Number ::= Digits ('.' Digits)?
3051 * | '.' Digits
3052 * [31] Digits ::= [0-9]+
3053 *
3054 * Parse and evaluate a Number, then push it on the stack
3055 *
3056 * BUG: "1.' is not valid ... James promised correction
3057 * as Digits ('.' Digits?)?
3058 */
3059void
3060xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003061 double ret = 0.0;
3062 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003063 int ok = 0;
3064
3065 CHECK_ERROR;
3066 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3067 ERROR(XPATH_NUMBER_ERROR);
3068 }
3069 while ((CUR >= '0') && (CUR <= '9')) {
3070 ret = ret * 10 + (CUR - '0');
3071 ok = 1;
3072 NEXT;
3073 }
3074 if (CUR == '.') {
3075 NEXT;
3076 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3077 ERROR(XPATH_NUMBER_ERROR);
3078 }
3079 while ((CUR >= '0') && (CUR <= '9')) {
3080 mult /= 10;
3081 ret = ret + (CUR - '0') * mult;
3082 NEXT;
3083 }
3084 }
3085 valuePush(ctxt, xmlXPathNewFloat(ret));
3086}
3087
3088/**
3089 * xmlXPathEvalLiteral:
3090 * @ctxt: the XPath Parser context
3091 *
3092 * Parse a Literal and push it on the stack.
3093 *
3094 * [29] Literal ::= '"' [^"]* '"'
3095 * | "'" [^']* "'"
3096 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003097 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003098 */
3099void
3100xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
3101 const CHAR *q;
3102 CHAR *ret = NULL;
3103
3104 if (CUR == '"') {
3105 NEXT;
3106 q = CUR_PTR;
3107 while ((IS_CHAR(CUR)) && (CUR != '"'))
3108 NEXT;
3109 if (!IS_CHAR(CUR)) {
3110 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3111 } else {
3112 ret = xmlStrndup(q, CUR_PTR - q);
3113 NEXT;
3114 }
3115 } else if (CUR == '\'') {
3116 NEXT;
3117 q = CUR_PTR;
3118 while ((IS_CHAR(CUR)) && (CUR != '\''))
3119 NEXT;
3120 if (!IS_CHAR(CUR)) {
3121 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3122 } else {
3123 ret = xmlStrndup(q, CUR_PTR - q);
3124 NEXT;
3125 }
3126 } else {
3127 ERROR(XPATH_START_LITERAL_ERROR);
3128 }
3129 if (ret == NULL) return;
3130 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003131 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003132}
3133
3134/**
3135 * xmlXPathEvalVariableReference:
3136 * @ctxt: the XPath Parser context
3137 *
3138 * Parse a VariableReference, evaluate it and push it on the stack.
3139 *
3140 * The variable bindings consist of a mapping from variable names
3141 * to variable values. The value of a variable is an object, which
3142 * of any of the types that are possible for the value of an expression,
3143 * and may also be of additional types not specified here.
3144 *
3145 * Early evaluation is possible since:
3146 * The variable bindings [...] used to evaluate a subexpression are
3147 * always the same as those used to evaluate the containing expression.
3148 *
3149 * [36] VariableReference ::= '$' QName
3150 */
3151void
3152xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
3153 CHAR *name;
3154 CHAR *prefix;
3155 xmlXPathObjectPtr value;
3156
3157 if (CUR != '$') {
3158 ERROR(XPATH_VARIABLE_REF_ERROR);
3159 }
3160 name = xmlXPathParseQName(ctxt, &prefix);
3161 if (name == NULL) {
3162 ERROR(XPATH_VARIABLE_REF_ERROR);
3163 }
3164 value = xmlXPathVariablelookup(ctxt, prefix, name);
3165 if (value == NULL) {
3166 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3167 }
3168 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003169 if (prefix != NULL) xmlFree(prefix);
3170 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003171}
3172
3173
3174/**
3175 * xmlXPathFunctionLookup:
3176 * @ctxt: the XPath Parser context
3177 * @name: a name string
3178 *
3179 * Search for a function of the given name
3180 *
3181 * [35] FunctionName ::= QName - NodeType
3182 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003183 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003184 *
3185 * Returns the xmlXPathFunction if found, or NULL otherwise
3186 */
3187xmlXPathFunction
Daniel Veillardb96e6431999-08-29 21:02:19 +00003188xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const CHAR *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003189 switch (name[0]) {
3190 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003191 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003192 return(xmlXPathBooleanFunction);
3193 break;
3194 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003195 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003196 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003197 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003198 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003199 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003200 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003201 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003202 return(xmlXPathContainsFunction);
3203 break;
3204 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003205 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003206 return(xmlXPathIdFunction);
3207 break;
3208 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003209 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003210 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003211 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003212 return(xmlXPathFloorFunction);
3213 break;
3214 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003215 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003216 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003217 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003218 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003219 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003220 return(xmlXPathLocalPartFunction);
3221 break;
3222 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003223 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003224 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003225 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003226 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003227 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003228 return(xmlXPathNamespaceFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003229 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003230 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003231 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003232 return(xmlXPathNumberFunction);
3233 break;
3234 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003235 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003236 return(xmlXPathPositionFunction);
3237 break;
3238 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003239 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003240 return(xmlXPathRoundFunction);
3241 break;
3242 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003243 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003244 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003245 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003246 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003247 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003248 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003249 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003250 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003251 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003252 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003253 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003254 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003255 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003256 return(xmlXPathSumFunction);
3257 break;
3258 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003259 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003260 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003261 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003262 return(xmlXPathTranslateFunction);
3263 break;
3264 }
3265 return(NULL);
3266}
3267
3268/**
3269 * xmlXPathEvalLocationPathName:
3270 * @ctxt: the XPath Parser context
3271 * @name: a name string
3272 *
3273 * Various names in the beginning of a LocationPath expression
3274 * indicate whether that's an Axis, a node type,
3275 *
3276 * [6] AxisName ::= 'ancestor'
3277 * | 'ancestor-or-self'
3278 * | 'attribute'
3279 * | 'child'
3280 * | 'descendant'
3281 * | 'descendant-or-self'
3282 * | 'following'
3283 * | 'following-sibling'
3284 * | 'namespace'
3285 * | 'parent'
3286 * | 'preceding'
3287 * | 'preceding-sibling'
3288 * | 'self'
3289 * [38] NodeType ::= 'comment'
3290 * | 'text'
3291 * | 'processing-instruction'
3292 * | 'node'
3293 */
3294int
Daniel Veillardb96e6431999-08-29 21:02:19 +00003295xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const CHAR *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003296 switch (name[0]) {
3297 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003298 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3299 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3300 return(AXIS_ANCESTOR_OR_SELF);
3301 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003302 break;
3303 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003304 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3305 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003306 break;
3307 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003308 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3309 return(AXIS_DESCENDANT);
3310 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3311 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003312 break;
3313 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003314 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3315 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3316 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003317 break;
3318 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003319 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3320 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003321 break;
3322 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003323 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3324 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3325 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3326 return(AXIS_PRECEDING_SIBLING);
3327 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3328 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003329 break;
3330 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003331 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003332 break;
3333 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003334 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003335 break;
3336 }
3337 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3338 return(0);
3339}
3340
3341/**
3342 * xmlXPathEvalFunctionCall:
3343 * @ctxt: the XPath Parser context
3344 *
3345 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3346 * [17] Argument ::= Expr
3347 *
3348 * Parse and evaluate a function call, the evaluation of all arguments are
3349 * pushed on the stack
3350 */
3351void
3352xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
3353 CHAR *name;
3354 CHAR *prefix;
3355 xmlXPathFunction func;
3356 int nbargs = 0;
3357
3358 name = xmlXPathParseQName(ctxt, &prefix);
3359 if (name == NULL) {
3360 ERROR(XPATH_EXPR_ERROR);
3361 }
3362 func = xmlXPathIsFunction(ctxt, name);
3363 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003364 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003365 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3366 }
3367#ifdef DEBUG_EXPR
3368 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3369#endif
3370
3371 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003372 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003373 ERROR(XPATH_EXPR_ERROR);
3374 }
3375 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003376
3377 while (CUR != ')') {
3378 xmlXPathEvalExpr(ctxt);
3379 nbargs++;
3380 if (CUR == ')') break;
3381 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003382 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003383 ERROR(XPATH_EXPR_ERROR);
3384 }
3385 NEXT;
3386 }
3387 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003388 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003389 func(ctxt, nbargs);
3390}
3391
3392/**
3393 * xmlXPathEvalPrimaryExpr:
3394 * @ctxt: the XPath Parser context
3395 *
3396 * [15] PrimaryExpr ::= VariableReference
3397 * | '(' Expr ')'
3398 * | Literal
3399 * | Number
3400 * | FunctionCall
3401 *
3402 * Parse and evaluate a primary expression, then push the result on the stack
3403 */
3404void
3405xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
3406 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3407 else if (CUR == '(') {
3408 NEXT;
3409 xmlXPathEvalExpr(ctxt);
3410 if (CUR != ')') {
3411 ERROR(XPATH_EXPR_ERROR);
3412 }
3413 NEXT;
3414 } else if (IS_DIGIT(CUR)) {
3415 xmlXPathEvalNumber(ctxt);
3416 } else if ((CUR == '\'') || (CUR == '"')) {
3417 xmlXPathEvalLiteral(ctxt);
3418 } else {
3419 xmlXPathEvalFunctionCall(ctxt);
3420 }
3421}
3422
3423/**
3424 * xmlXPathEvalFilterExpr:
3425 * @ctxt: the XPath Parser context
3426 *
3427 * [20] FilterExpr ::= PrimaryExpr
3428 * | FilterExpr Predicate
3429 *
3430 * Parse and evaluate a filter expression, then push the result on the stack
3431 * Square brackets are used to filter expressions in the same way that
3432 * they are used in location paths. It is an error if the expression to
3433 * be filtered does not evaluate to a node-set. The context node list
3434 * used for evaluating the expression in square brackets is the node-set
3435 * to be filtered listed in document order.
3436 */
3437
3438void
3439xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3440 /****
3441 xmlNodeSetPtr oldset = NULL;
3442 xmlXPathObjectPtr arg;
3443 ****/
3444
3445 xmlXPathEvalPrimaryExpr(ctxt);
3446 CHECK_ERROR;
3447
3448 if (CUR != '[') return;
3449
3450 CHECK_TYPE(XPATH_NODESET);
3451
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003452 while (CUR == '[') {
3453 xmlXPathEvalPredicate(ctxt);
3454 }
3455
3456
3457}
3458
3459/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003460 * xmlXPathScanName:
3461 * @ctxt: the XPath Parser context
3462 *
3463 * Trickery: parse an XML name but without consuming the input flow
3464 * Needed for rollback cases.
3465 *
3466 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3467 * CombiningChar | Extender
3468 *
3469 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3470 *
3471 * [6] Names ::= Name (S Name)*
3472 *
3473 * Returns the Name parsed or NULL
3474 */
3475
3476CHAR *
3477xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
3478 CHAR buf[XML_MAX_NAMELEN];
3479 int len = 0;
3480
3481 if (!IS_LETTER(CUR) && (CUR != '_') &&
3482 (CUR != ':')) {
3483 return(NULL);
3484 }
3485
3486 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3487 (NXT(len) == '.') || (NXT(len) == '-') ||
3488 (NXT(len) == '_') || (NXT(len) == ':') ||
3489 (IS_COMBINING(NXT(len))) ||
3490 (IS_EXTENDER(NXT(len)))) {
3491 buf[len] = NXT(len);
3492 len++;
3493 if (len >= XML_MAX_NAMELEN) {
3494 fprintf(stderr,
3495 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3496 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3497 (NXT(len) == '.') || (NXT(len) == '-') ||
3498 (NXT(len) == '_') || (NXT(len) == ':') ||
3499 (IS_COMBINING(NXT(len))) ||
3500 (IS_EXTENDER(NXT(len))))
3501 len++;
3502 break;
3503 }
3504 }
3505 return(xmlStrndup(buf, len));
3506}
3507
3508/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003509 * xmlXPathEvalPathExpr:
3510 * @ctxt: the XPath Parser context
3511 *
3512 * [19] PathExpr ::= LocationPath
3513 * | FilterExpr
3514 * | FilterExpr '/' RelativeLocationPath
3515 * | FilterExpr '//' RelativeLocationPath
3516 *
3517 * Parse and evaluate a path expression, then push the result on the stack
3518 * The / operator and // operators combine an arbitrary expression
3519 * and a relative location path. It is an error if the expression
3520 * does not evaluate to a node-set.
3521 * The / operator does composition in the same way as when / is
3522 * used in a location path. As in location paths, // is short for
3523 * /descendant-or-self::node()/.
3524 */
3525
3526void
3527xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3528 xmlNodeSetPtr newset = NULL;
3529
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003530 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3531 (CUR == '\'') || (CUR == '"')) {
3532 xmlXPathEvalFilterExpr(ctxt);
3533 CHECK_ERROR;
3534 if ((CUR == '/') && (NXT(1) == '/')) {
3535 SKIP(2);
3536 if (ctxt->context->nodelist == NULL) {
3537 STRANGE
3538 xmlXPathRoot(ctxt);
3539 }
3540 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3541 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3542 if (ctxt->context->nodelist != NULL)
3543 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3544 ctxt->context->nodelist = newset;
3545 ctxt->context->node = NULL;
3546 xmlXPathEvalRelativeLocationPath(ctxt);
3547 } else if (CUR == '/') {
3548 xmlXPathEvalRelativeLocationPath(ctxt);
3549 }
3550 } else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003551 CHAR *name;
3552
3553 name = xmlXPathScanName(ctxt);
3554 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3555 xmlXPathEvalLocationPath(ctxt);
3556 else
3557 xmlXPathEvalFilterExpr(ctxt);
3558 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003559 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003560 }
3561}
3562
3563/**
3564 * xmlXPathEvalUnionExpr:
3565 * @ctxt: the XPath Parser context
3566 *
3567 * [18] UnionExpr ::= PathExpr
3568 * | UnionExpr '|' PathExpr
3569 *
3570 * Parse and evaluate an union expression, then push the result on the stack
3571 */
3572
3573void
3574xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3575 xmlXPathEvalPathExpr(ctxt);
3576 CHECK_ERROR;
3577 if (CUR == '|') {
3578 xmlNodeSetPtr old = ctxt->context->nodelist;
3579
3580 xmlXPathEvalPathExpr(ctxt);
3581
3582 if (ctxt->context->nodelist == NULL)
3583 ctxt->context->nodelist = old;
3584 else {
3585 ctxt->context->nodelist =
3586 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3587 xmlXPathFreeNodeSet(old);
3588 }
3589 }
3590}
3591
3592/**
3593 * xmlXPathEvalUnaryExpr:
3594 * @ctxt: the XPath Parser context
3595 *
3596 * [27] UnaryExpr ::= UnionExpr
3597 * | '-' UnaryExpr
3598 *
3599 * Parse and evaluate an unary expression, then push the result on the stack
3600 */
3601
3602void
3603xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3604 int minus = 0;
3605
3606 if (CUR == '-') {
3607 minus = 1;
3608 NEXT;
3609 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003610 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003611 CHECK_ERROR;
3612 if (minus) {
3613 xmlXPathValueFlipSign(ctxt);
3614 }
3615}
3616
3617/**
3618 * xmlXPathEvalMultiplicativeExpr:
3619 * @ctxt: the XPath Parser context
3620 *
3621 * [26] MultiplicativeExpr ::= UnaryExpr
3622 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3623 * | MultiplicativeExpr 'div' UnaryExpr
3624 * | MultiplicativeExpr 'mod' UnaryExpr
3625 * [34] MultiplyOperator ::= '*'
3626 *
3627 * Parse and evaluate an Additive expression, then push the result on the stack
3628 */
3629
3630void
3631xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3632 xmlXPathEvalUnaryExpr(ctxt);
3633 CHECK_ERROR;
3634 while ((CUR == '*') ||
3635 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3636 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3637 int op = -1;
3638
3639 if (CUR == '*') {
3640 op = 0;
3641 NEXT;
3642 } else if (CUR == 'd') {
3643 op = 1;
3644 SKIP(3);
3645 } else if (CUR == 'm') {
3646 op = 2;
3647 SKIP(3);
3648 }
3649 xmlXPathEvalUnaryExpr(ctxt);
3650 CHECK_ERROR;
3651 switch (op) {
3652 case 0:
3653 xmlXPathMultValues(ctxt);
3654 break;
3655 case 1:
3656 xmlXPathDivValues(ctxt);
3657 break;
3658 case 2:
3659 xmlXPathModValues(ctxt);
3660 break;
3661 }
3662 }
3663}
3664
3665/**
3666 * xmlXPathEvalAdditiveExpr:
3667 * @ctxt: the XPath Parser context
3668 *
3669 * [25] AdditiveExpr ::= MultiplicativeExpr
3670 * | AdditiveExpr '+' MultiplicativeExpr
3671 * | AdditiveExpr '-' MultiplicativeExpr
3672 *
3673 * Parse and evaluate an Additive expression, then push the result on the stack
3674 */
3675
3676void
3677xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3678 xmlXPathEvalMultiplicativeExpr(ctxt);
3679 CHECK_ERROR;
3680 while ((CUR == '+') || (CUR == '-')) {
3681 int plus;
3682
3683 if (CUR == '+') plus = 1;
3684 else plus = 0;
3685 NEXT;
3686 xmlXPathEvalMultiplicativeExpr(ctxt);
3687 CHECK_ERROR;
3688 if (plus) xmlXPathAddValues(ctxt);
3689 else xmlXPathSubValues(ctxt);
3690 }
3691}
3692
3693/**
3694 * xmlXPathEvalRelationalExpr:
3695 * @ctxt: the XPath Parser context
3696 *
3697 * [24] RelationalExpr ::= AdditiveExpr
3698 * | RelationalExpr '<' AdditiveExpr
3699 * | RelationalExpr '>' AdditiveExpr
3700 * | RelationalExpr '<=' AdditiveExpr
3701 * | RelationalExpr '>=' AdditiveExpr
3702 *
3703 * A <= B > C is allowed ? Answer from James, yes with
3704 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3705 * which is basically what got implemented.
3706 *
3707 * Parse and evaluate a Relational expression, then push the result
3708 * on the stack
3709 */
3710
3711void
3712xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3713 xmlXPathEvalAdditiveExpr(ctxt);
3714 CHECK_ERROR;
3715 while ((CUR == '<') ||
3716 (CUR == '>') ||
3717 ((CUR == '<') && (NXT(1) == '=')) ||
3718 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003719 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003720
3721 if (CUR == '<') inf = 1;
3722 else inf = 0;
3723 if (NXT(1) == '=') strict = 0;
3724 else strict = 1;
3725 NEXT;
3726 if (!strict) NEXT;
3727 xmlXPathEvalAdditiveExpr(ctxt);
3728 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003729 ret = xmlXPathCompareValues(ctxt, inf, strict);
3730 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003731 }
3732}
3733
3734/**
3735 * xmlXPathEvalEqualityExpr:
3736 * @ctxt: the XPath Parser context
3737 *
3738 * [23] EqualityExpr ::= RelationalExpr
3739 * | EqualityExpr '=' RelationalExpr
3740 * | EqualityExpr '!=' RelationalExpr
3741 *
3742 * A != B != C is allowed ? Answer from James, yes with
3743 * (RelationalExpr = RelationalExpr) = RelationalExpr
3744 * (RelationalExpr != RelationalExpr) != RelationalExpr
3745 * which is basically what got implemented.
3746 *
3747 * Parse and evaluate an Equality expression, then push the result on the stack
3748 *
3749 */
3750void
3751xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3752 xmlXPathEvalRelationalExpr(ctxt);
3753 CHECK_ERROR;
3754 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003755 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003756 int eq, equal;
3757
3758 if (CUR == '=') eq = 1;
3759 else eq = 0;
3760 NEXT;
3761 if (!eq) NEXT;
3762 xmlXPathEvalRelationalExpr(ctxt);
3763 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003764 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003765 if (eq) res = xmlXPathNewBoolean(equal);
3766 else res = xmlXPathNewBoolean(!equal);
3767 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003768 }
3769}
3770
3771/**
3772 * xmlXPathEvalAndExpr:
3773 * @ctxt: the XPath Parser context
3774 *
3775 * [22] AndExpr ::= EqualityExpr
3776 * | AndExpr 'and' EqualityExpr
3777 *
3778 * Parse and evaluate an AND expression, then push the result on the stack
3779 *
3780 */
3781void
3782xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3783 xmlXPathEvalEqualityExpr(ctxt);
3784 CHECK_ERROR;
3785 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3786 xmlXPathObjectPtr arg1, arg2;
3787
3788 SKIP(3);
3789 xmlXPathEvalEqualityExpr(ctxt);
3790 CHECK_ERROR;
3791 arg2 = valuePop(ctxt);
3792 arg1 = valuePop(ctxt);
3793 arg1->boolval &= arg2->boolval;
3794 valuePush(ctxt, arg1);
3795 xmlXPathFreeObject(arg2);
3796 }
3797}
3798
3799/**
3800 * xmlXPathEvalExpr:
3801 * @ctxt: the XPath Parser context
3802 *
3803 * [14] Expr ::= OrExpr
3804 * [21] OrExpr ::= AndExpr
3805 * | OrExpr 'or' AndExpr
3806 *
3807 * Parse and evaluate an expression, then push the result on the stack
3808 *
3809 */
3810void
3811xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3812 xmlXPathEvalAndExpr(ctxt);
3813 CHECK_ERROR;
3814 while ((CUR == 'o') && (NXT(1) == 'r')) {
3815 xmlXPathObjectPtr arg1, arg2;
3816
3817 SKIP(2);
3818 xmlXPathEvalAndExpr(ctxt);
3819 CHECK_ERROR;
3820 arg2 = valuePop(ctxt);
3821 arg1 = valuePop(ctxt);
3822 arg1->boolval |= arg2->boolval;
3823 valuePush(ctxt, arg1);
3824 xmlXPathFreeObject(arg2);
3825 }
3826}
3827
3828/**
3829 * xmlXPathEvaluatePredicateResult:
3830 * @ctxt: the XPath Parser context
3831 * @res: the Predicate Expression evaluation result
3832 * @index: index of the current node in the current list
3833 *
3834 * Evaluate a predicate result for the current node.
3835 * A PredicateExpr is evaluated by evaluating the Expr and converting
3836 * the result to a boolean. If the result is a number, the result will
3837 * be converted to true if the number is equal to the position of the
3838 * context node in the context node list (as returned by the position
3839 * function) and will be converted to false otherwise; if the result
3840 * is not a number, then the result will be converted as if by a call
3841 * to the boolean function.
3842 */
3843int
3844xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3845 xmlXPathObjectPtr res, int index) {
3846 if (res == NULL) return(0);
3847 switch (res->type) {
3848 case XPATH_BOOLEAN:
3849 return(res->boolval);
3850 case XPATH_NUMBER:
3851 return(res->floatval == index);
3852 case XPATH_NODESET:
3853 return(res->nodesetval->nodeNr != 0);
3854 case XPATH_STRING:
3855 return((res->stringval != NULL) &&
3856 (xmlStrlen(res->stringval) != 0));
3857 default:
3858 STRANGE
3859 }
3860 return(0);
3861}
3862
3863/**
3864 * xmlXPathEvalPredicate:
3865 * @ctxt: the XPath Parser context
3866 *
3867 * [8] Predicate ::= '[' PredicateExpr ']'
3868 * [9] PredicateExpr ::= Expr
3869 *
3870 * Parse and evaluate a predicate for all the elements of the
3871 * current node list. Then refine the list by removing all
3872 * nodes where the predicate is false.
3873 */
3874void
3875xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
3876 const CHAR *cur;
3877 xmlXPathObjectPtr res;
3878 xmlNodeSetPtr newset = NULL;
3879 int i;
3880
3881 if (CUR != '[') {
3882 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3883 }
3884 NEXT;
3885 if ((ctxt->context->nodelist == NULL) ||
3886 (ctxt->context->nodelist->nodeNr == 0)) {
3887 ctxt->context->node = NULL;
3888 xmlXPathEvalExpr(ctxt);
3889 CHECK_ERROR;
3890 res = valuePop(ctxt);
3891 if (res != NULL)
3892 xmlXPathFreeObject(res);
3893 } else {
3894 cur = ctxt->cur;
3895 newset = xmlXPathNodeSetCreate(NULL);
3896 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3897 ctxt->cur = cur;
3898 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3899 xmlXPathEvalExpr(ctxt);
3900 CHECK_ERROR;
3901 res = valuePop(ctxt);
3902 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3903 xmlXPathNodeSetAdd(newset,
3904 ctxt->context->nodelist->nodeTab[i]);
3905 if (res != NULL)
3906 xmlXPathFreeObject(res);
3907 }
3908 if (ctxt->context->nodelist != NULL)
3909 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3910 ctxt->context->nodelist = newset;
3911 ctxt->context->node = NULL;
3912 }
3913 if (CUR != ']') {
3914 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3915 }
3916 NEXT;
3917#ifdef DEBUG_STEP
3918 fprintf(xmlXPathDebug, "After predicate : ");
3919 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3920#endif
3921}
3922
3923/**
3924 * xmlXPathEvalBasis:
3925 * @ctxt: the XPath Parser context
3926 *
3927 * [5] Basis ::= AxisName '::' NodeTest
3928 * | AbbreviatedBasis
3929 * [13] AbbreviatedBasis ::= NodeTest
3930 * | '@' NodeTest
3931 * [7] NodeTest ::= WildcardName
3932 * | NodeType '(' ')'
3933 * | 'processing-instruction' '(' Literal ')'
3934 * [37] WildcardName ::= '*'
3935 * | NCName ':' '*'
3936 * | QName
3937 *
3938 * Evaluate one step in a Location Path
3939 */
3940void
3941xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
3942 CHAR *name = NULL;
3943 CHAR *prefix = NULL;
3944 int type = 0;
3945 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
3946 int nodetest = NODE_TEST_NONE;
3947 int nodetype = 0;
3948 xmlNodeSetPtr newset = NULL;
3949
3950 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003951 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003952 axis = AXIS_ATTRIBUTE;
3953 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003954 } else if (CUR == '*') {
3955 NEXT;
3956 nodetest = NODE_TEST_ALL;
3957 } else {
3958 name = xmlXPathParseNCName(ctxt);
3959 if (name == NULL) {
3960 ERROR(XPATH_EXPR_ERROR);
3961 }
3962 type = xmlXPathGetNameType(ctxt, name);
3963 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003964 case IS_FUNCTION: {
3965 xmlXPathFunction func;
3966 int nbargs = 0;
3967 xmlXPathObjectPtr top;
3968
3969 top = ctxt->value;
3970 func = xmlXPathIsFunction(ctxt, name);
3971 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003972 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003973 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3974 }
3975#ifdef DEBUG_EXPR
3976 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3977#endif
3978
3979 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003980 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003981 ERROR(XPATH_EXPR_ERROR);
3982 }
3983 NEXT;
3984
3985 while (CUR != ')') {
3986 xmlXPathEvalExpr(ctxt);
3987 nbargs++;
3988 if (CUR == ')') break;
3989 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003990 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003991 ERROR(XPATH_EXPR_ERROR);
3992 }
3993 NEXT;
3994 }
3995 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003996 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003997 func(ctxt, nbargs);
3998 if ((ctxt->value != top) &&
3999 (ctxt->value != NULL) &&
4000 (ctxt->value->type == XPATH_NODESET)) {
4001 xmlXPathObjectPtr cur;
4002
4003 cur = valuePop(ctxt);
4004 ctxt->context->nodelist = cur->nodesetval;
4005 ctxt->context->node = NULL;
4006 cur->nodesetval = NULL;
4007 xmlXPathFreeObject(cur);
4008 }
4009 return;
4010 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004011 /*
4012 * Simple case: no axis seach all given node types.
4013 */
4014 case NODE_TYPE_COMMENT:
4015 if ((CUR != '(') || (NXT(1) != ')')) break;
4016 SKIP(2);
4017 nodetest = NODE_TEST_TYPE;
4018 nodetype = XML_COMMENT_NODE;
4019 goto search_nodes;
4020 case NODE_TYPE_TEXT:
4021 if ((CUR != '(') || (NXT(1) != ')')) break;
4022 SKIP(2);
4023 nodetest = NODE_TEST_TYPE;
4024 nodetype = XML_TEXT_NODE;
4025 goto search_nodes;
4026 case NODE_TYPE_NODE:
4027 if ((CUR != '(') || (NXT(1) != ')')) {
4028 nodetest = NODE_TEST_NAME;
4029 break;
4030 }
4031 SKIP(2);
4032 nodetest = NODE_TEST_TYPE;
4033 nodetype = XML_ELEMENT_NODE;
4034 goto search_nodes;
4035 case NODE_TYPE_PI:
4036 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004037 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004038 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004039 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004040 xmlXPathObjectPtr cur;
4041
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004042 /*
4043 * Specific case: search a PI by name.
4044 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004045 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004046 nodetest = NODE_TEST_PI;
4047 xmlXPathEvalLiteral(ctxt);
4048 CHECK_ERROR;
4049 if (CUR != ')')
4050 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004051 NEXT;
4052 xmlXPathStringFunction(ctxt, 1);
4053 CHECK_ERROR;
4054 cur = valuePop(ctxt);
4055 name = xmlStrdup(cur->stringval);
4056 xmlXPathFreeObject(cur);
4057 } else
4058 SKIP(2);
4059 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004060 goto search_nodes;
4061
4062 /*
4063 * Handling of the compund form: got the axis.
4064 */
4065 case AXIS_ANCESTOR:
4066 case AXIS_ANCESTOR_OR_SELF:
4067 case AXIS_ATTRIBUTE:
4068 case AXIS_CHILD:
4069 case AXIS_DESCENDANT:
4070 case AXIS_DESCENDANT_OR_SELF:
4071 case AXIS_FOLLOWING:
4072 case AXIS_FOLLOWING_SIBLING:
4073 case AXIS_NAMESPACE:
4074 case AXIS_PARENT:
4075 case AXIS_PRECEDING:
4076 case AXIS_PRECEDING_SIBLING:
4077 case AXIS_SELF:
4078 if ((CUR != ':') || (NXT(1) != ':')) {
4079 nodetest = NODE_TEST_NAME;
4080 break;
4081 }
4082 SKIP(2);
4083 axis = type;
4084 break;
4085
4086 /*
4087 * Default: abbreviated syntax the axis is AXIS_CHILD
4088 */
4089 default:
4090 nodetest = NODE_TEST_NAME;
4091 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004092parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004093 if (nodetest == NODE_TEST_NONE) {
4094 if (CUR == '*') {
4095 NEXT;
4096 nodetest = NODE_TEST_ALL;
4097 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004098 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004099 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004100 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004101 if (name == NULL) {
4102 ERROR(XPATH_EXPR_ERROR);
4103 }
4104 type = xmlXPathGetNameType(ctxt, name);
4105 switch (type) {
4106 /*
4107 * Simple case: no axis seach all given node types.
4108 */
4109 case NODE_TYPE_COMMENT:
4110 if ((CUR != '(') || (NXT(1) != ')')) break;
4111 SKIP(2);
4112 nodetest = NODE_TEST_TYPE;
4113 nodetype = XML_COMMENT_NODE;
4114 goto search_nodes;
4115 case NODE_TYPE_TEXT:
4116 if ((CUR != '(') || (NXT(1) != ')')) break;
4117 SKIP(2);
4118 nodetest = NODE_TEST_TYPE;
4119 nodetype = XML_TEXT_NODE;
4120 goto search_nodes;
4121 case NODE_TYPE_NODE:
4122 if ((CUR != '(') || (NXT(1) != ')')) {
4123 nodetest = NODE_TEST_NAME;
4124 break;
4125 }
4126 SKIP(2);
4127 nodetest = NODE_TEST_TYPE;
4128 nodetype = XML_ELEMENT_NODE;
4129 goto search_nodes;
4130 case NODE_TYPE_PI:
4131 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004132 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004133 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004134 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004135 xmlXPathObjectPtr cur;
4136
Daniel Veillardb05deb71999-08-10 19:04:08 +00004137 /*
4138 * Specific case: search a PI by name.
4139 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004140 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004141 nodetest = NODE_TEST_PI;
4142 xmlXPathEvalLiteral(ctxt);
4143 CHECK_ERROR;
4144 if (CUR != ')')
4145 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004146 NEXT;
4147 xmlXPathStringFunction(ctxt, 1);
4148 CHECK_ERROR;
4149 cur = valuePop(ctxt);
4150 name = xmlStrdup(cur->stringval);
4151 xmlXPathFreeObject(cur);
4152 } else
4153 SKIP(2);
4154 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004155 goto search_nodes;
4156 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004157 nodetest = NODE_TEST_NAME;
4158 }
4159 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4160 NEXT;
4161 prefix = name;
4162 if (CUR == '*') {
4163 NEXT;
4164 nodetest = NODE_TEST_ALL;
4165 } else
4166 name = xmlXPathParseNCName(ctxt);
4167 } else if (name == NULL)
4168 ERROR(XPATH_EXPR_ERROR);
4169 }
4170
4171search_nodes:
4172
4173#ifdef DEBUG_STEP
4174 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4175#endif
4176 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4177 prefix, name);
4178 if (ctxt->context->nodelist != NULL)
4179 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4180 ctxt->context->nodelist = newset;
4181 ctxt->context->node = NULL;
4182#ifdef DEBUG_STEP
4183 fprintf(xmlXPathDebug, "Basis : ");
4184 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4185#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004186 if (name != NULL) xmlFree(name);
4187 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004188}
4189
4190/**
4191 * xmlXPathEvalStep:
4192 * @ctxt: the XPath Parser context
4193 *
4194 * [4] Step ::= Basis Predicate*
4195 * | AbbreviatedStep
4196 * [12] AbbreviatedStep ::= '.'
4197 * | '..'
4198 *
4199 * Evaluate one step in a Location Path
4200 * A location step of . is short for self::node(). This is
4201 * particularly useful in conjunction with //. For example, the
4202 * location path .//para is short for
4203 * self::node()/descendant-or-self::node()/child::para
4204 * and so will select all para descendant elements of the context
4205 * node.
4206 * Similarly, a location step of .. is short for parent::node().
4207 * For example, ../title is short for parent::node()/child::title
4208 * and so will select the title children of the parent of the context
4209 * node.
4210 */
4211void
4212xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4213 xmlNodeSetPtr newset = NULL;
4214
4215 if ((CUR == '.') && (NXT(1) == '.')) {
4216 SKIP(2);
4217 if (ctxt->context->nodelist == NULL) {
4218 STRANGE
4219 xmlXPathRoot(ctxt);
4220 }
4221 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4222 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4223 if (ctxt->context->nodelist != NULL)
4224 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4225 ctxt->context->nodelist = newset;
4226 ctxt->context->node = NULL;
4227 } else if (CUR == '.') {
4228 NEXT;
4229 } else {
4230 xmlXPathEvalBasis(ctxt);
4231 while (CUR == '[') {
4232 xmlXPathEvalPredicate(ctxt);
4233 }
4234 }
4235#ifdef DEBUG_STEP
4236 fprintf(xmlXPathDebug, "Step : ");
4237 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4238#endif
4239}
4240
4241/**
4242 * xmlXPathEvalRelativeLocationPath:
4243 * @ctxt: the XPath Parser context
4244 *
4245 * [3] RelativeLocationPath ::= Step
4246 * | RelativeLocationPath '/' Step
4247 * | AbbreviatedRelativeLocationPath
4248 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4249 *
4250 */
4251void
4252xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4253 xmlNodeSetPtr newset = NULL;
4254
4255 xmlXPathEvalStep(ctxt);
4256 while (CUR == '/') {
4257 if ((CUR == '/') && (NXT(1) == '/')) {
4258 SKIP(2);
4259 if (ctxt->context->nodelist == NULL) {
4260 STRANGE
4261 xmlXPathRoot(ctxt);
4262 }
4263 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4264 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4265 if (ctxt->context->nodelist != NULL)
4266 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4267 ctxt->context->nodelist = newset;
4268 ctxt->context->node = NULL;
4269 xmlXPathEvalStep(ctxt);
4270 } else if (CUR == '/') {
4271 NEXT;
4272 xmlXPathEvalStep(ctxt);
4273 }
4274 }
4275}
4276
4277/**
4278 * xmlXPathEvalLocationPath:
4279 * @ctxt: the XPath Parser context
4280 *
4281 * [1] LocationPath ::= RelativeLocationPath
4282 * | AbsoluteLocationPath
4283 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4284 * | AbbreviatedAbsoluteLocationPath
4285 * [10] AbbreviatedAbsoluteLocationPath ::=
4286 * '//' RelativeLocationPath
4287 *
4288 * // is short for /descendant-or-self::node()/. For example,
4289 * //para is short for /descendant-or-self::node()/child::para and
4290 * so will select any para element in the document (even a para element
4291 * that is a document element will be selected by //para since the
4292 * document element node is a child of the root node); div//para is
4293 * short for div/descendant-or-self::node()/child::para and so will
4294 * select all para descendants of div children.
4295 */
4296void
4297xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4298 xmlNodeSetPtr newset = NULL;
4299
4300 while (CUR == '/') {
4301 if ((CUR == '/') && (NXT(1) == '/')) {
4302 SKIP(2);
4303 if (ctxt->context->nodelist == NULL)
4304 xmlXPathRoot(ctxt);
4305 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4306 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4307 if (ctxt->context->nodelist != NULL)
4308 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4309 ctxt->context->nodelist = newset;
4310 ctxt->context->node = NULL;
4311 xmlXPathEvalRelativeLocationPath(ctxt);
4312 } else if (CUR == '/') {
4313 NEXT;
4314 xmlXPathRoot(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004315 if (CUR != 0)
4316 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004317 } else {
4318 xmlXPathEvalRelativeLocationPath(ctxt);
4319 }
4320 }
4321}
4322
4323/*
4324 * TODO * extra spaces *
4325 * more tokenization rules ... Not used currently, especially allowing
4326 * spaces before and after ExprToken !!!!!!!!!!!!!
4327 *
4328 * [32] Operator ::= OperatorName
4329 * | MultiplyOperator
4330 * | '/' | '//' | '|' | '+' | '-' | '=' | '!='
4331 * | '<'| '<=' | '>' | '>='
4332 * [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
4333 * [39] ExprWhitespace ::= S
4334 *
4335 * BUG: ExprToken is never referenced.
4336 *
4337 * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
4338 * | WildcardName
4339 * | NodeType
4340 * | Operator
4341 * | FunctionName
4342 * | AxisName
4343 * | Literal
4344 * | Number
4345 * | VariableReference
4346 */
4347
4348/**
4349 * xmlXPathEval:
4350 * @str: the XPath expression
4351 * @ctxt: the XPath context
4352 *
4353 * Evaluate the XPath Location Path in the given context.
4354 *
4355 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4356 * the caller has to free the object.
4357 */
4358xmlXPathObjectPtr
4359xmlXPathEval(const CHAR *str, xmlXPathContextPtr ctxt) {
4360 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004361 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004362
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004363 xmlXPathInit();
4364
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004365 CHECK_CONTEXT
4366
4367 if (xmlXPathDebug == NULL)
4368 xmlXPathDebug = stderr;
4369 pctxt = xmlXPathNewParserContext(str, ctxt);
4370 xmlXPathEvalLocationPath(pctxt);
4371
Daniel Veillardb96e6431999-08-29 21:02:19 +00004372 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004373 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004374 tmp = valuePop(pctxt);
4375 if (tmp != NULL);
4376 xmlXPathFreeObject(tmp);
4377 } while (tmp != NULL);
4378 if (res == NULL)
4379 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004380 xmlXPathFreeParserContext(pctxt);
4381 return(res);
4382}
4383
4384/**
4385 * xmlXPathEvalExpression:
4386 * @str: the XPath expression
4387 * @ctxt: the XPath context
4388 *
4389 * Evaluate the XPath expression in the given context.
4390 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004391 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004392 * the caller has to free the object.
4393 */
4394xmlXPathObjectPtr
4395xmlXPathEvalExpression(const CHAR *str, xmlXPathContextPtr ctxt) {
4396 xmlXPathParserContextPtr pctxt;
4397 xmlXPathObjectPtr res, tmp;
4398
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004399 xmlXPathInit();
4400
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004401 CHECK_CONTEXT
4402
4403 if (xmlXPathDebug == NULL)
4404 xmlXPathDebug = stderr;
4405 pctxt = xmlXPathNewParserContext(str, ctxt);
4406 xmlXPathEvalExpr(pctxt);
4407
4408 res = valuePop(pctxt);
4409 do {
4410 tmp = valuePop(pctxt);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004411 if (tmp != NULL);
4412 xmlXPathFreeObject(tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004413 } while (tmp != NULL);
4414 xmlXPathFreeParserContext(pctxt);
4415 return(res);
4416}
4417