blob: 94c7f5ae67fc1be03f9f678e5be2b5604af1a985 [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 Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
17#define HAVE_FCNTL_H
18#include <io.h>
19#else
20#include "config.h"
21#endif
22
23#include <stdio.h>
24#include <string.h>
25
26#ifdef HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000029#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000030#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000031#endif
32#ifdef HAVE_MATH_H
33#include <float.h>
34#endif
35#ifdef HAVE_IEEEFP_H
36#include <ieeefp.h>
37#endif
38#ifdef HAVE_NAN_H
39#include <nan.h>
40#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000041#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000042#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000043#endif
44
Daniel Veillard6454aec1999-09-02 22:04:43 +000045#include "xmlmemory.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000046#include "tree.h"
Daniel Veillardb96e6431999-08-29 21:02:19 +000047#include "valid.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000048#include "xpath.h"
49#include "parserInternals.h"
50
51/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000052 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000053 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000054 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000055double xmlXPathNAN = 0;
56double xmlXPathPINF = 1;
57double xmlXPathMINF = -1;
58
Daniel Veillardb05deb71999-08-10 19:04:08 +000059#ifndef isinf
60#ifndef HAVE_ISINF
61
62#if HAVE_FPCLASS
63
64int isinf(double d) {
65 fpclass_t type = fpclass(d);
66 switch (type) {
67 case FP_NINF:
68 return(-1);
69 case FP_PINF:
70 return(1);
71 default:
72 return(0);
73 }
74 return(0);
75}
76
77#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
78
79#if HAVE_FP_CLASS_H
80#include <fp_class.h>
81#endif
82
83int isinf(double d) {
84#if HAVE_FP_CLASS
85 int fpclass = fp_class(d);
86#else
87 int fpclass = fp_class_d(d);
88#endif
89 if (fpclass == FP_POS_INF)
90 return(1);
91 if (fpclass == FP_NEG_INF)
92 return(-1);
93 return(0);
94}
95
96#elif defined(HAVE_CLASS)
97
98int isinf(double d) {
99 int fpclass = class(d);
100 if (fpclass == FP_PLUS_INF)
101 return(1);
102 if (fpclass == FP_MINUS_INF)
103 return(-1);
104 return(0);
105}
106#elif defined(finite) || defined(HAVE_FINITE)
107int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000108#elif defined(HUGE_VAL)
109static int isinf(double x)
110{
111 if (x == HUGE_VAL)
112 return(1);
113 if (x == -HUGE_VAL)
114 return(-1);
115 return(0);
116}
117#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000118
119#endif /* ! HAVE_ISINF */
120#endif /* ! defined(isinf) */
121
122#ifndef isnan
123#ifndef HAVE_ISNAN
124
125#ifdef HAVE_ISNAND
126#define isnan(f) isnand(f)
127#endif /* HAVE_iSNAND */
128
129#endif /* ! HAVE_iSNAN */
130#endif /* ! defined(isnan) */
131
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000132/**
133 * xmlXPathInit:
134 *
135 * Initialize the XPath environment
136 */
137void
138xmlXPathInit(void) {
139 static int initialized = 0;
140
141 if (initialized) return;
142
143 xmlXPathNAN = 0;
144 xmlXPathNAN /= 0;
145
146 xmlXPathPINF = 1;
147 xmlXPathPINF /= 0;
148
149 xmlXPathMINF = -1;
150 xmlXPathMINF /= 0;
151
152 initialized = 1;
153}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000154
155/* #define DEBUG */
156/* #define DEBUG_STEP */
157/* #define DEBUG_EXPR */
158
159FILE *xmlXPathDebug = NULL;
160
161#define TODO \
162 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
163 __FILE__, __LINE__);
164
165#define STRANGE \
166 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
167 __FILE__, __LINE__);
168
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000169double xmlXPathStringEvalNumber(const CHAR *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000170void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000171
172/************************************************************************
173 * *
174 * Parser stacks related functions and macros *
175 * *
176 ************************************************************************/
177
178/*
179 * Generic function for accessing stacks in the Parser Context
180 */
181
182#define PUSH_AND_POP(type, name) \
183extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
184 if (ctxt->name##Nr >= ctxt->name##Max) { \
185 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000186 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000187 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
188 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000189 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000190 exit(1); \
191 } \
192 } \
193 ctxt->name##Tab[ctxt->name##Nr] = value; \
194 ctxt->name = value; \
195 return(ctxt->name##Nr++); \
196} \
197extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
198 type ret; \
199 if (ctxt->name##Nr <= 0) return(0); \
200 ctxt->name##Nr--; \
201 if (ctxt->name##Nr > 0) \
202 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
203 else \
204 ctxt->name = NULL; \
205 ret = ctxt->name##Tab[ctxt->name##Nr]; \
206 ctxt->name##Tab[ctxt->name##Nr] = 0; \
207 return(ret); \
208} \
209
210PUSH_AND_POP(xmlXPathObjectPtr, value)
211
212/*
213 * Macros for accessing the content. Those should be used only by the parser,
214 * and not exported.
215 *
216 * Dirty macros, i.e. one need to make assumption on the context to use them
217 *
218 * CUR_PTR return the current pointer to the CHAR to be parsed.
219 * CUR returns the current CHAR value, i.e. a 8 bit value if compiled
220 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
221 * in UNICODE mode. This should be used internally by the parser
222 * only to compare to ASCII values otherwise it would break when
223 * running with UTF-8 encoding.
224 * NXT(n) returns the n'th next CHAR. Same as CUR is should be used only
225 * to compare on ASCII based substring.
226 * SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
227 * strings within the parser.
228 * CURRENT Returns the current char value, with the full decoding of
229 * UTF-8 if we are using this mode. It returns an int.
230 * NEXT Skip to the next character, this does the proper decoding
231 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
232 * It returns the pointer to the current CHAR.
233 */
234
235#define CUR (*ctxt->cur)
236#define SKIP(val) ctxt->cur += (val)
237#define NXT(val) ctxt->cur[(val)]
238#define CUR_PTR ctxt->cur
239
240#define SKIP_BLANKS \
241 while (IS_BLANK(*(ctxt->cur))) NEXT
242
243#ifndef USE_UTF_8
244#define CURRENT (*ctxt->cur)
245#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
246#else
247#endif
248
249/************************************************************************
250 * *
251 * Error handling routines *
252 * *
253 ************************************************************************/
254
255#define XPATH_EXPRESSION_OK 0
256#define XPATH_NUMBER_ERROR 1
257#define XPATH_UNFINISHED_LITERAL_ERROR 2
258#define XPATH_START_LITERAL_ERROR 3
259#define XPATH_VARIABLE_REF_ERROR 4
260#define XPATH_UNDEF_VARIABLE_ERROR 5
261#define XPATH_INVALID_PREDICATE_ERROR 6
262#define XPATH_EXPR_ERROR 7
263#define XPATH_UNCLOSED_ERROR 8
264#define XPATH_UNKNOWN_FUNC_ERROR 9
265#define XPATH_INVALID_OPERAND 10
266#define XPATH_INVALID_TYPE 11
267#define XPATH_INVALID_ARITY 12
268
269const char *xmlXPathErrorMessages[] = {
270 "Ok",
271 "Number encoding",
272 "Unfinished litteral",
273 "Start of litteral",
274 "Expected $ for variable reference",
275 "Undefined variable",
276 "Invalid predicate",
277 "Invalid expression",
278 "Missing closing curly brace",
279 "Unregistered function",
280 "Invalid operand",
281 "Invalid type",
282 "Invalid number of arguments",
283};
284
285/**
286 * xmlXPathError:
287 * @ctxt: the XPath Parser context
288 * @file: the file name
289 * @line: the line number
290 * @no: the error number
291 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000292 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000293 *
294 * Returns the newly created object.
295 */
296void
297xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
298 int line, int no) {
299 int n;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000300 const CHAR *cur;
301 const CHAR *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000302
303 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
304 xmlXPathErrorMessages[no]);
305
306 cur = ctxt->cur;
307 base = ctxt->base;
308 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
309 cur--;
310 }
311 n = 0;
312 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
313 cur--;
314 if ((*cur == '\n') || (*cur == '\r')) cur++;
315 base = cur;
316 n = 0;
317 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
318 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
319 n++;
320 }
321 fprintf(xmlXPathDebug, "\n");
322 cur = ctxt->cur;
323 while ((*cur == '\n') || (*cur == '\r'))
324 cur--;
325 n = 0;
326 while ((cur != base) && (n++ < 80)) {
327 fprintf(xmlXPathDebug, " ");
328 base++;
329 }
330 fprintf(xmlXPathDebug,"^\n");
331}
332
333#define CHECK_ERROR \
334 if (ctxt->error != XPATH_EXPRESSION_OK) return
335
336#define ERROR(X) \
337 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
338 ctxt->error = (X); return; }
339
Daniel Veillard991e63d1999-08-15 23:32:28 +0000340#define ERROR0(X) \
341 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
342 ctxt->error = (X); return(0); }
343
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000344#define CHECK_TYPE(typeval) \
345 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
346 ERROR(XPATH_INVALID_TYPE) \
347
348
349/************************************************************************
350 * *
351 * Routines to handle NodeSets *
352 * *
353 ************************************************************************/
354
355#define XML_NODESET_DEFAULT 10
356/**
357 * xmlXPathNodeSetCreate:
358 * @val: an initial xmlNodePtr, or NULL
359 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000360 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000361 *
362 * Returns the newly created object.
363 */
364xmlNodeSetPtr
365xmlXPathNodeSetCreate(xmlNodePtr val) {
366 xmlNodeSetPtr ret;
367
Daniel Veillard6454aec1999-09-02 22:04:43 +0000368 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000369 if (ret == NULL) {
370 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
371 return(NULL);
372 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000373 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000374 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000375 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000376 sizeof(xmlNodePtr));
377 if (ret->nodeTab == NULL) {
378 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
379 return(NULL);
380 }
381 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000382 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000383 ret->nodeMax = XML_NODESET_DEFAULT;
384 ret->nodeTab[ret->nodeNr++] = val;
385 }
386 return(ret);
387}
388
389/**
390 * xmlXPathNodeSetAdd:
391 * @cur: the initial node set
392 * @val: a new xmlNodePtr
393 *
394 * add a new xmlNodePtr ot an existing NodeSet
395 */
396void
397xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
398 int i;
399
400 if (val == NULL) return;
401
402 /*
403 * check against doublons
404 */
405 for (i = 0;i < cur->nodeNr;i++)
406 if (cur->nodeTab[i] == val) return;
407
408 /*
409 * grow the nodeTab if needed
410 */
411 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000412 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000413 sizeof(xmlNodePtr));
414 if (cur->nodeTab == NULL) {
415 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
416 return;
417 }
418 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000419 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000420 cur->nodeMax = XML_NODESET_DEFAULT;
421 } else if (cur->nodeNr == cur->nodeMax) {
422 xmlNodePtr *temp;
423
424 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000425 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000426 sizeof(xmlNodePtr));
427 if (temp == NULL) {
428 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
429 return;
430 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000431 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000432 }
433 cur->nodeTab[cur->nodeNr++] = val;
434}
435
436/**
437 * xmlXPathNodeSetMerge:
438 * @val1: the first NodeSet
439 * @val2: the second NodeSet
440 *
441 * Merges two nodesets, all nodes from @val2 are added to @val1
442 *
443 * Returns val1 once extended or NULL in case of error.
444 */
445xmlNodeSetPtr
446xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
447 int i;
448
449 if (val1 == NULL) return(NULL);
450 if (val2 == NULL) return(val1);
451
452 /*
453 * !!!!! this can be optimized a lot, knowing that both
454 * val1 and val2 already have unicity of their values.
455 */
456
457 for (i = 0;i < val2->nodeNr;i++)
458 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
459
460 return(val1);
461}
462
463/**
464 * xmlXPathNodeSetDel:
465 * @cur: the initial node set
466 * @val: an xmlNodePtr
467 *
468 * Removes an xmlNodePtr from an existing NodeSet
469 */
470void
471xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
472 int i;
473
474 if (cur == NULL) return;
475 if (val == NULL) return;
476
477 /*
478 * check against doublons
479 */
480 for (i = 0;i < cur->nodeNr;i++)
481 if (cur->nodeTab[i] == val) break;
482
483 if (i >= cur->nodeNr) {
484#ifdef DEBUG
485 fprintf(xmlXPathDebug,
486 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
487 val->name);
488#endif
489 return;
490 }
491 cur->nodeNr--;
492 for (;i < cur->nodeNr;i++)
493 cur->nodeTab[i] = cur->nodeTab[i + 1];
494 cur->nodeTab[cur->nodeNr] = NULL;
495}
496
497/**
498 * xmlXPathNodeSetRemove:
499 * @cur: the initial node set
500 * @val: the index to remove
501 *
502 * Removes an entry from an existing NodeSet list.
503 */
504void
505xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
506 if (cur == NULL) return;
507 if (val >= cur->nodeNr) return;
508 cur->nodeNr--;
509 for (;val < cur->nodeNr;val++)
510 cur->nodeTab[val] = cur->nodeTab[val + 1];
511 cur->nodeTab[cur->nodeNr] = NULL;
512}
513
514/**
515 * xmlXPathFreeNodeSet:
516 * @obj: the xmlNodeSetPtr to free
517 *
518 * Free the NodeSet compound (not the actual nodes !).
519 */
520void
521xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
522 if (obj == NULL) return;
523 if (obj->nodeTab != NULL) {
524#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000525 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000526#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000527 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000528 }
529#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000530 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000531#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000532 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000533}
534
Daniel Veillardb96e6431999-08-29 21:02:19 +0000535#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000536/**
537 * xmlXPathDebugNodeSet:
538 * @output: a FILE * for the output
539 * @obj: the xmlNodeSetPtr to free
540 *
541 * Quick display of a NodeSet
542 */
543void
544xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
545 int i;
546
547 if (output == NULL) output = xmlXPathDebug;
548 if (obj == NULL) {
549 fprintf(output, "NodeSet == NULL !\n");
550 return;
551 }
552 if (obj->nodeNr == 0) {
553 fprintf(output, "NodeSet is empty\n");
554 return;
555 }
556 if (obj->nodeTab == NULL) {
557 fprintf(output, " nodeTab == NULL !\n");
558 return;
559 }
560 for (i = 0; i < obj->nodeNr; i++) {
561 if (obj->nodeTab[i] == NULL) {
562 fprintf(output, " NULL !\n");
563 return;
564 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000565 if (obj->nodeTab[i]->type == XML_DOCUMENT_NODE)
566 fprintf(output, " /");
567 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000568 fprintf(output, " noname!");
569 else fprintf(output, " %s", obj->nodeTab[i]->name);
570 }
571 fprintf(output, "\n");
572}
573#endif
574
575/************************************************************************
576 * *
577 * Routines to handle Variable *
578 * *
579 * UNIMPLEMENTED CURRENTLY *
580 * *
581 ************************************************************************/
582
583/**
584 * xmlXPathVariablelookup:
585 * @ctxt: the XPath Parser context
586 * @prefix: the variable name namespace if any
587 * @name: the variable name
588 *
589 * Search in the Variable array of the context for the given
590 * variable value.
591 *
592 * UNIMPLEMENTED: always return NULL.
593 *
594 * Returns the value or NULL if not found
595 */
596xmlXPathObjectPtr
597xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
598 const CHAR *prefix, const CHAR *name) {
599 return(NULL);
600}
601
602/************************************************************************
603 * *
604 * Routines to handle Values *
605 * *
606 ************************************************************************/
607
608/* Allocations are terrible, one need to optimize all this !!! */
609
610/**
611 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000612 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000613 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000614 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000615 *
616 * Returns the newly created object.
617 */
618xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000619xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000620 xmlXPathObjectPtr ret;
621
Daniel Veillard6454aec1999-09-02 22:04:43 +0000622 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000623 if (ret == NULL) {
624 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
625 return(NULL);
626 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000627 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000628 ret->type = XPATH_NUMBER;
629 ret->floatval = val;
630 return(ret);
631}
632
633/**
634 * xmlXPathNewBoolean:
635 * @val: the boolean value
636 *
637 * Create a new xmlXPathObjectPtr of type boolean and of value @val
638 *
639 * Returns the newly created object.
640 */
641xmlXPathObjectPtr
642xmlXPathNewBoolean(int val) {
643 xmlXPathObjectPtr ret;
644
Daniel Veillard6454aec1999-09-02 22:04:43 +0000645 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000646 if (ret == NULL) {
647 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
648 return(NULL);
649 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000650 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000651 ret->type = XPATH_BOOLEAN;
652 ret->boolval = (val != 0);
653 return(ret);
654}
655
656/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000657 * xmlXPathNewString:
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000658 * @val: the CHAR * value
659 *
660 * Create a new xmlXPathObjectPtr of type string and of value @val
661 *
662 * Returns the newly created object.
663 */
664xmlXPathObjectPtr
665xmlXPathNewString(const CHAR *val) {
666 xmlXPathObjectPtr ret;
667
Daniel Veillard6454aec1999-09-02 22:04:43 +0000668 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000669 if (ret == NULL) {
670 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
671 return(NULL);
672 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000673 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000674 ret->type = XPATH_STRING;
675 ret->stringval = xmlStrdup(val);
676 return(ret);
677}
678
679/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000680 * xmlXPathNewCString:
681 * @val: the char * value
682 *
683 * Create a new xmlXPathObjectPtr of type string and of value @val
684 *
685 * Returns the newly created object.
686 */
687xmlXPathObjectPtr
688xmlXPathNewCString(const char *val) {
689 xmlXPathObjectPtr ret;
690
Daniel Veillard6454aec1999-09-02 22:04:43 +0000691 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000692 if (ret == NULL) {
693 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
694 return(NULL);
695 }
696 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
697 ret->type = XPATH_STRING;
698 ret->stringval = xmlStrdup(BAD_CAST val);
699 return(ret);
700}
701
702/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000703 * xmlXPathNewNodeSet:
704 * @val: the NodePtr value
705 *
706 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
707 * it with the single Node @val
708 *
709 * Returns the newly created object.
710 */
711xmlXPathObjectPtr
712xmlXPathNewNodeSet(xmlNodePtr val) {
713 xmlXPathObjectPtr ret;
714
Daniel Veillard6454aec1999-09-02 22:04:43 +0000715 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000716 if (ret == NULL) {
717 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
718 return(NULL);
719 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000720 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000721 ret->type = XPATH_NODESET;
722 ret->nodesetval = xmlXPathNodeSetCreate(val);
723 return(ret);
724}
725
726/**
727 * xmlXPathNewNodeSetList:
728 * @val: an existing NodeSet
729 *
730 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
731 * it with the Nodeset @val
732 *
733 * Returns the newly created object.
734 */
735xmlXPathObjectPtr
736xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
737 xmlXPathObjectPtr ret;
738
Daniel Veillard6454aec1999-09-02 22:04:43 +0000739 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000740 if (ret == NULL) {
741 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
742 return(NULL);
743 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000744 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000745 ret->type = XPATH_NODESET;
746 ret->nodesetval = val;
747 return(ret);
748}
749
750/**
751 * xmlXPathFreeObject:
752 * @obj: the object to free
753 *
754 * Free up an xmlXPathObjectPtr object.
755 */
756void
757xmlXPathFreeObject(xmlXPathObjectPtr obj) {
758 if (obj == NULL) return;
759 if (obj->nodesetval != NULL)
760 xmlXPathFreeNodeSet(obj->nodesetval);
761 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000762 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000763#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000764 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000765#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000766 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000767}
768
769/************************************************************************
770 * *
771 * Routines to handle XPath contexts *
772 * *
773 ************************************************************************/
774
775/**
776 * xmlXPathNewContext:
777 * @doc: the XML document
778 * @variables: the variable list
779 * @functions: the function list
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000780 *
781 * Create a new xmlXPathContext
782 *
783 * Returns the xmlXPathContext just allocated.
784 */
785xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000786xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000787 xmlXPathContextPtr ret;
788
Daniel Veillard6454aec1999-09-02 22:04:43 +0000789 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000790 if (ret == NULL) {
791 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
792 return(NULL);
793 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000794 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000795 ret->doc = doc;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000796
797 ret->nb_variables = 0;
798 ret->max_variables = 0;
799 ret->variables = NULL;
800
801 ret->nb_types = 0;
802 ret->max_types = 0;
803 ret->types = NULL;
804
805 ret->nb_funcs = 0;
806 ret->max_funcs = 0;
807 ret->funcs = NULL;
808
809 ret->nb_axis = 0;
810 ret->max_axis = 0;
811 ret->axis = NULL;
812
Daniel Veillardb96e6431999-08-29 21:02:19 +0000813 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000814 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000815 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000816 return(ret);
817}
818
819/**
820 * xmlXPathFreeContext:
821 * @ctxt: the context to free
822 *
823 * Free up an xmlXPathContext
824 */
825void
826xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000827 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000828 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000829
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000830#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000831 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000832#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000833 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000834}
835
836/************************************************************************
837 * *
838 * Routines to handle XPath parser contexts *
839 * *
840 ************************************************************************/
841
842#define CHECK_CTXT \
843 if (ctxt == NULL) { \
844 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
845 __FILE__, __LINE__); \
846 } \
847
848
849#define CHECK_CONTEXT \
850 if (ctxt == NULL) { \
851 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
852 __FILE__, __LINE__); \
853 } \
854 if (ctxt->doc == NULL) { \
855 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
856 __FILE__, __LINE__); \
857 } \
858 if (ctxt->doc->root == NULL) { \
859 fprintf(xmlXPathDebug, \
860 "%s:%d Internal error: document without root\n", \
861 __FILE__, __LINE__); \
862 } \
863
864
865/**
866 * xmlXPathNewParserContext:
867 * @str: the XPath expression
868 * @ctxt: the XPath context
869 *
870 * Create a new xmlXPathParserContext
871 *
872 * Returns the xmlXPathParserContext just allocated.
873 */
874xmlXPathParserContextPtr
875xmlXPathNewParserContext(const CHAR *str, xmlXPathContextPtr ctxt) {
876 xmlXPathParserContextPtr ret;
877
Daniel Veillard6454aec1999-09-02 22:04:43 +0000878 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000879 if (ret == NULL) {
880 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
881 return(NULL);
882 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000883 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000884 ret->cur = ret->base = str;
885 ret->context = ctxt;
886
887 /* Allocate the value stack */
888 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000889 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000890 ret->valueNr = 0;
891 ret->valueMax = 10;
892 ret->value = NULL;
893 return(ret);
894}
895
896/**
897 * xmlXPathFreeParserContext:
898 * @ctxt: the context to free
899 *
900 * Free up an xmlXPathParserContext
901 */
902void
903xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
904 if (ctxt->valueTab != NULL) {
905#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000906 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000907#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000908 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000909 }
910#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000911 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000912#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000913 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000914}
915
916/************************************************************************
917 * *
918 * The implicit core function library *
919 * *
920 ************************************************************************/
921
922/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000923 * Auto-pop and cast to a number
924 */
925void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
926
927#define CHECK_ARITY(x) \
928 if (nargs != (x)) { \
929 ERROR(XPATH_INVALID_ARITY); \
930 } \
931
932
933#define POP_FLOAT \
934 arg = valuePop(ctxt); \
935 if (arg == NULL) { \
936 ERROR(XPATH_INVALID_OPERAND); \
937 } \
938 if (arg->type != XPATH_NUMBER) { \
939 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000940 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000941 arg = valuePop(ctxt); \
942 }
943
944/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000945 * xmlXPathEqualNodeSetString
946 * @arg: the nodeset object argument
947 * @str: the string to compare to.
948 *
949 * Implement the equal operation on XPath objects content: @arg1 == @arg2
950 * If one object to be compared is a node-set and the other is a string,
951 * then the comparison will be true if and only if there is a node in
952 * the node-set such that the result of performing the comparison on the
953 * string-value of the node and the other string is true.
954 *
955 * Returns 0 or 1 depending on the results of the test.
956 */
957int
958xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const CHAR *str) {
959 int i;
960 xmlNodeSetPtr ns;
961 CHAR *str2;
962
963 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
964 return(0);
965 ns = arg->nodesetval;
966 for (i = 0;i < ns->nodeNr;i++) {
967 str2 = xmlNodeGetContent(ns->nodeTab[i]);
968 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000969 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000970 return(1);
971 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000972 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000973 }
974 return(0);
975}
976
977/**
978 * xmlXPathEqualNodeSetFloat
979 * @arg: the nodeset object argument
980 * @f: the float to compare to
981 *
982 * Implement the equal operation on XPath objects content: @arg1 == @arg2
983 * If one object to be compared is a node-set and the other is a number,
984 * then the comparison will be true if and only if there is a node in
985 * the node-set such that the result of performing the comparison on the
986 * number to be compared and on the result of converting the string-value
987 * of that node to a number using the number function is true.
988 *
989 * Returns 0 or 1 depending on the results of the test.
990 */
991int
992xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000993 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +0000994
995 if ((arg == NULL) || (arg->type != XPATH_NODESET))
996 return(0);
997
998 if (isnan(f))
999 sprintf(buf, "NaN");
1000 else if (isinf(f) > 0)
1001 sprintf(buf, "+Infinity");
1002 else if (isinf(f) < 0)
1003 sprintf(buf, "-Infinity");
1004 else
1005 sprintf(buf, "%0g", f);
1006
Daniel Veillardb96e6431999-08-29 21:02:19 +00001007 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001008}
1009
1010
1011/**
1012 * xmlXPathEqualNodeSets
1013 * @arg1: first nodeset object argument
1014 * @arg2: second nodeset object argument
1015 *
1016 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1017 * If both objects to be compared are node-sets, then the comparison
1018 * will be true if and only if there is a node in the first node-set and
1019 * a node in the second node-set such that the result of performing the
1020 * comparison on the string-values of the two nodes is true.
1021 *
1022 * (needless to say, this is a costly operation)
1023 *
1024 * Returns 0 or 1 depending on the results of the test.
1025 */
1026int
1027xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1028 int i;
1029 xmlNodeSetPtr ns;
1030 CHAR *str;
1031
1032 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1033 return(0);
1034 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1035 return(0);
1036
1037 ns = arg1->nodesetval;
1038 for (i = 0;i < ns->nodeNr;i++) {
1039 str = xmlNodeGetContent(ns->nodeTab[i]);
1040 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001041 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001042 return(1);
1043 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001044 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001045 }
1046 return(0);
1047}
1048
1049/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001050 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001051 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001052 *
1053 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1054 *
1055 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001056 */
1057int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001058xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1059 xmlXPathObjectPtr arg1, arg2;
1060 int ret = 0;
1061
1062 arg1 = valuePop(ctxt);
1063 if (arg1 == NULL)
1064 ERROR0(XPATH_INVALID_OPERAND);
1065
1066 arg2 = valuePop(ctxt);
1067 if (arg2 == NULL) {
1068 xmlXPathFreeObject(arg1);
1069 ERROR0(XPATH_INVALID_OPERAND);
1070 }
1071
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001072 if (arg1 == arg2) {
1073#ifdef DEBUG_EXPR
1074 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1075#endif
1076 return(1);
1077 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001078
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001079 switch (arg1->type) {
1080 case XPATH_UNDEFINED:
1081#ifdef DEBUG_EXPR
1082 fprintf(xmlXPathDebug, "Equal: undefined\n");
1083#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001084 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001085 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001086 switch (arg2->type) {
1087 case XPATH_UNDEFINED:
1088#ifdef DEBUG_EXPR
1089 fprintf(xmlXPathDebug, "Equal: undefined\n");
1090#endif
1091 break;
1092 case XPATH_NODESET:
1093 ret = xmlXPathEqualNodeSets(arg1, arg2);
1094 break;
1095 case XPATH_BOOLEAN:
1096 if ((arg1->nodesetval == NULL) ||
1097 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1098 else
1099 ret = 1;
1100 ret = (ret == arg2->boolval);
1101 break;
1102 case XPATH_NUMBER:
1103 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1104 break;
1105 case XPATH_STRING:
1106 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1107 break;
1108 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001109 break;
1110 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001111 switch (arg2->type) {
1112 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001113#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001114 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001115#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001116 break;
1117 case XPATH_NODESET:
1118 if ((arg2->nodesetval == NULL) ||
1119 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1120 else
1121 ret = 1;
1122 break;
1123 case XPATH_BOOLEAN:
1124#ifdef DEBUG_EXPR
1125 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1126 arg1->boolval, arg2->boolval);
1127#endif
1128 ret = (arg1->boolval == arg2->boolval);
1129 break;
1130 case XPATH_NUMBER:
1131 if (arg2->floatval) ret = 1;
1132 else ret = 0;
1133 ret = (arg1->boolval == ret);
1134 break;
1135 case XPATH_STRING:
1136 if ((arg2->stringval == NULL) ||
1137 (arg2->stringval[0] == 0)) ret = 0;
1138 else
1139 ret = 1;
1140 ret = (arg1->boolval == ret);
1141 break;
1142 }
1143 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001144 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001145 switch (arg2->type) {
1146 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001147#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001148 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001149#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001150 break;
1151 case XPATH_NODESET:
1152 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1153 break;
1154 case XPATH_BOOLEAN:
1155 if (arg1->floatval) ret = 1;
1156 else ret = 0;
1157 ret = (arg2->boolval == ret);
1158 break;
1159 case XPATH_STRING:
1160 valuePush(ctxt, arg2);
1161 xmlXPathNumberFunction(ctxt, 1);
1162 arg2 = valuePop(ctxt);
1163 /* no break on purpose */
1164 case XPATH_NUMBER:
1165 ret = (arg1->floatval == arg2->floatval);
1166 break;
1167 }
1168 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001169 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001170 switch (arg2->type) {
1171 case XPATH_UNDEFINED:
1172#ifdef DEBUG_EXPR
1173 fprintf(xmlXPathDebug, "Equal: undefined\n");
1174#endif
1175 break;
1176 case XPATH_NODESET:
1177 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1178 break;
1179 case XPATH_BOOLEAN:
1180 if ((arg1->stringval == NULL) ||
1181 (arg1->stringval[0] == 0)) ret = 0;
1182 else
1183 ret = 1;
1184 ret = (arg2->boolval == ret);
1185 break;
1186 case XPATH_STRING:
1187 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1188 break;
1189 case XPATH_NUMBER:
1190 valuePush(ctxt, arg1);
1191 xmlXPathNumberFunction(ctxt, 1);
1192 arg1 = valuePop(ctxt);
1193 ret = (arg1->floatval == arg2->floatval);
1194 break;
1195 }
1196 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001197#ifdef DEBUG_EXPR
1198 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
1199 arg1->stringval, arg2->stringval);
1200#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001201 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001202 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001203 xmlXPathFreeObject(arg1);
1204 xmlXPathFreeObject(arg2);
1205 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001206}
1207
1208/**
1209 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001210 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001211 * @inf: less than (1) or greater than (2)
1212 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001213 *
1214 * Implement the compare operation on XPath objects:
1215 * @arg1 < @arg2 (1, 1, ...
1216 * @arg1 <= @arg2 (1, 0, ...
1217 * @arg1 > @arg2 (0, 1, ...
1218 * @arg1 >= @arg2 (0, 0, ...
1219 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001220 * When neither object to be compared is a node-set and the operator is
1221 * <=, <, >=, >, then the objects are compared by converted both objects
1222 * to numbers and comparing the numbers according to IEEE 754. The <
1223 * comparison will be true if and only if the first number is less than the
1224 * second number. The <= comparison will be true if and only if the first
1225 * number is less than or equal to the second number. The > comparison
1226 * will be true if and only if the first number is greater than the second
1227 * number. The >= comparison will be true if and only if the first number
1228 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001229 */
1230int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001231xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1232 int ret = 0;
1233 xmlXPathObjectPtr arg1, arg2;
1234
1235 arg2 = valuePop(ctxt);
1236 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1237 if (arg2 != NULL)
1238 xmlXPathFreeObject(arg2);
1239 ERROR0(XPATH_INVALID_OPERAND);
1240 }
1241
1242 arg1 = valuePop(ctxt);
1243 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1244 if (arg1 != NULL)
1245 xmlXPathFreeObject(arg1);
1246 xmlXPathFreeObject(arg2);
1247 ERROR0(XPATH_INVALID_OPERAND);
1248 }
1249
1250 if (arg1->type != XPATH_NUMBER) {
1251 valuePush(ctxt, arg1);
1252 xmlXPathNumberFunction(ctxt, 1);
1253 arg1 = valuePop(ctxt);
1254 }
1255 if (arg1->type != XPATH_NUMBER) {
1256 xmlXPathFreeObject(arg1);
1257 xmlXPathFreeObject(arg2);
1258 ERROR0(XPATH_INVALID_OPERAND);
1259 }
1260 if (arg2->type != XPATH_NUMBER) {
1261 valuePush(ctxt, arg2);
1262 xmlXPathNumberFunction(ctxt, 1);
1263 arg2 = valuePop(ctxt);
1264 }
1265 if (arg2->type != XPATH_NUMBER) {
1266 xmlXPathFreeObject(arg1);
1267 xmlXPathFreeObject(arg2);
1268 ERROR0(XPATH_INVALID_OPERAND);
1269 }
1270 /*
1271 * Add tests for infinity and nan
1272 * => feedback on 3.4 for Inf and NaN
1273 */
1274 if (inf && strict)
1275 ret = (arg1->floatval < arg2->floatval);
1276 else if (inf && !strict)
1277 ret = (arg1->floatval <= arg2->floatval);
1278 else if (!inf && strict)
1279 ret = (arg1->floatval > arg2->floatval);
1280 else if (!inf && !strict)
1281 ret = (arg1->floatval >= arg2->floatval);
1282 xmlXPathFreeObject(arg1);
1283 xmlXPathFreeObject(arg2);
1284 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001285}
1286
1287/**
1288 * xmlXPathValueFlipSign:
1289 * @ctxt: the XPath Parser context
1290 *
1291 * Implement the unary - operation on an XPath object
1292 * The numeric operators convert their operands to numbers as if
1293 * by calling the number function.
1294 */
1295void
1296xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1297 xmlXPathObjectPtr arg;
1298
1299 POP_FLOAT
1300 arg->floatval = -arg->floatval;
1301 valuePush(ctxt, arg);
1302}
1303
1304/**
1305 * xmlXPathAddValues:
1306 * @ctxt: the XPath Parser context
1307 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001308 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001309 * The numeric operators convert their operands to numbers as if
1310 * by calling the number function.
1311 */
1312void
1313xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1314 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001315 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001316
1317 POP_FLOAT
1318 val = arg->floatval;
1319 xmlXPathFreeObject(arg);
1320
1321 POP_FLOAT
1322 arg->floatval += val;
1323 valuePush(ctxt, arg);
1324}
1325
1326/**
1327 * xmlXPathSubValues:
1328 * @ctxt: the XPath Parser context
1329 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001330 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001331 * The numeric operators convert their operands to numbers as if
1332 * by calling the number function.
1333 */
1334void
1335xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1336 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001337 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001338
1339 POP_FLOAT
1340 val = arg->floatval;
1341 xmlXPathFreeObject(arg);
1342
1343 POP_FLOAT
1344 arg->floatval -= val;
1345 valuePush(ctxt, arg);
1346}
1347
1348/**
1349 * xmlXPathMultValues:
1350 * @ctxt: the XPath Parser context
1351 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001352 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001353 * The numeric operators convert their operands to numbers as if
1354 * by calling the number function.
1355 */
1356void
1357xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1358 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001359 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001360
1361 POP_FLOAT
1362 val = arg->floatval;
1363 xmlXPathFreeObject(arg);
1364
1365 POP_FLOAT
1366 arg->floatval *= val;
1367 valuePush(ctxt, arg);
1368}
1369
1370/**
1371 * xmlXPathDivValues:
1372 * @ctxt: the XPath Parser context
1373 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001374 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001375 * The numeric operators convert their operands to numbers as if
1376 * by calling the number function.
1377 */
1378void
1379xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1380 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001381 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001382
1383 POP_FLOAT
1384 val = arg->floatval;
1385 xmlXPathFreeObject(arg);
1386
1387 POP_FLOAT
1388 arg->floatval /= val;
1389 valuePush(ctxt, arg);
1390}
1391
1392/**
1393 * xmlXPathModValues:
1394 * @ctxt: the XPath Parser context
1395 *
1396 * Implement the div operation on XPath objects: @arg1 / @arg2
1397 * The numeric operators convert their operands to numbers as if
1398 * by calling the number function.
1399 */
1400void
1401xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1402 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001403 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001404
1405 POP_FLOAT
1406 val = arg->floatval;
1407 xmlXPathFreeObject(arg);
1408
1409 POP_FLOAT
1410 arg->floatval /= val;
1411 valuePush(ctxt, arg);
1412}
1413
1414/************************************************************************
1415 * *
1416 * The traversal functions *
1417 * *
1418 ************************************************************************/
1419
1420#define AXIS_ANCESTOR 1
1421#define AXIS_ANCESTOR_OR_SELF 2
1422#define AXIS_ATTRIBUTE 3
1423#define AXIS_CHILD 4
1424#define AXIS_DESCENDANT 5
1425#define AXIS_DESCENDANT_OR_SELF 6
1426#define AXIS_FOLLOWING 7
1427#define AXIS_FOLLOWING_SIBLING 8
1428#define AXIS_NAMESPACE 9
1429#define AXIS_PARENT 10
1430#define AXIS_PRECEDING 11
1431#define AXIS_PRECEDING_SIBLING 12
1432#define AXIS_SELF 13
1433
1434/*
1435 * A traversal function enumerates nodes along an axis.
1436 * Initially it must be called with NULL, and it indicates
1437 * termination on the axis by returning NULL.
1438 */
1439typedef xmlNodePtr (*xmlXPathTraversalFunction)
1440 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1441
1442/**
1443 * mlXPathNextSelf:
1444 * @ctxt: the XPath Parser context
1445 * @cur: the current node in the traversal
1446 *
1447 * Traversal function for the "self" direction
1448 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001449 *
1450 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001451 */
1452xmlNodePtr
1453xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1454 if (cur == NULL)
1455 return(ctxt->context->node);
1456 return(NULL);
1457}
1458
1459/**
1460 * mlXPathNextChild:
1461 * @ctxt: the XPath Parser context
1462 * @cur: the current node in the traversal
1463 *
1464 * Traversal function for the "child" direction
1465 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001466 *
1467 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001468 */
1469xmlNodePtr
1470xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001471 if (cur == NULL) {
1472 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1473 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001474 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001475 }
1476 if (ctxt->context->node->type == XML_DOCUMENT_NODE)
1477 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001478 return(cur->next);
1479}
1480
1481/**
1482 * mlXPathNextDescendant:
1483 * @ctxt: the XPath Parser context
1484 * @cur: the current node in the traversal
1485 *
1486 * Traversal function for the "descendant" direction
1487 * the descendant axis contains the descendants of the context node in document
1488 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001489 *
1490 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001491 */
1492xmlNodePtr
1493xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001494 if (cur == NULL) {
1495 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1496 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001497 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001498 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001499
1500 if (cur->childs != NULL) return(cur->childs);
1501 if (cur->next != NULL) return(cur->next);
1502
1503 do {
1504 cur = cur->parent;
1505 if (cur == NULL) return(NULL);
1506 if (cur == ctxt->context->node) return(NULL);
1507 if (cur->next != NULL) {
1508 cur = cur->next;
1509 return(cur);
1510 }
1511 } while (cur != NULL);
1512 return(cur);
1513}
1514
1515/**
1516 * mlXPathNextDescendantOrSelf:
1517 * @ctxt: the XPath Parser context
1518 * @cur: the current node in the traversal
1519 *
1520 * Traversal function for the "descendant-or-self" direction
1521 * the descendant-or-self axis contains the context node and the descendants
1522 * of the context node in document order; thus the context node is the first
1523 * node on the axis, and the first child of the context node is the second node
1524 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001525 *
1526 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001527 */
1528xmlNodePtr
1529xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1530 if (cur == NULL)
1531 return(ctxt->context->node);
1532
Daniel Veillardb05deb71999-08-10 19:04:08 +00001533 if (cur == (xmlNodePtr) ctxt->context->doc)
1534 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001535 if (cur->childs != NULL) return(cur->childs);
1536 if (cur->next != NULL) return(cur->next);
1537
1538 do {
1539 cur = cur->parent;
1540 if (cur == NULL) return(NULL);
1541 if (cur == ctxt->context->node) return(NULL);
1542 if (cur->next != NULL) {
1543 cur = cur->next;
1544 return(cur);
1545 }
1546 } while (cur != NULL);
1547 return(cur);
1548}
1549
1550/**
1551 * xmlXPathNextParent:
1552 * @ctxt: the XPath Parser context
1553 * @cur: the current node in the traversal
1554 *
1555 * Traversal function for the "parent" direction
1556 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001557 *
1558 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001559 */
1560xmlNodePtr
1561xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1562 /*
1563 * !!!!!!!!!!!!!
1564 * the parent of an attribute or namespace node is the element
1565 * to which the attribute or namespace node is attached
1566 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001567 if (cur == NULL) {
1568 if (ctxt->context->node->parent == NULL)
1569 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001570 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001571 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001572 return(NULL);
1573}
1574
1575/**
1576 * xmlXPathNextAncestor:
1577 * @ctxt: the XPath Parser context
1578 * @cur: the current node in the traversal
1579 *
1580 * Traversal function for the "ancestor" direction
1581 * the ancestor axis contains the ancestors of the context node; the ancestors
1582 * of the context node consist of the parent of context node and the parent's
1583 * parent and so on; the nodes are ordered in reverse document order; thus the
1584 * parent is the first node on the axis, and the parent's parent is the second
1585 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001586 *
1587 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001588 */
1589xmlNodePtr
1590xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1591 /*
1592 * !!!!!!!!!!!!!
1593 * the parent of an attribute or namespace node is the element
1594 * to which the attribute or namespace node is attached
1595 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001596 if (cur == NULL) {
1597 if (ctxt->context->node->parent == NULL)
1598 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001599 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001600 }
1601 if (cur == ctxt->context->doc->root)
1602 return((xmlNodePtr) ctxt->context->doc);
1603 if (cur == (xmlNodePtr) ctxt->context->doc)
1604 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001605 return(cur->parent);
1606}
1607
1608/**
1609 * xmlXPathNextAncestorOrSelf:
1610 * @ctxt: the XPath Parser context
1611 * @cur: the current node in the traversal
1612 *
1613 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001614 * he ancestor-or-self axis contains the context node and ancestors of
1615 * the context node in reverse document order; thus the context node is
1616 * the first node on the axis, and the context node's parent the second;
1617 * parent here is defined the same as with the parent axis.
1618 *
1619 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001620 */
1621xmlNodePtr
1622xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1623 /*
1624 * !!!!!!!!!!!!!
1625 * the parent of an attribute or namespace node is the element
1626 * to which the attribute or namespace node is attached
1627 */
1628 if (cur == NULL)
1629 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001630 if (cur == ctxt->context->doc->root)
1631 return((xmlNodePtr) ctxt->context->doc);
1632 if (cur == (xmlNodePtr) ctxt->context->doc)
1633 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001634 return(cur->parent);
1635}
1636
1637/**
1638 * xmlXPathNextFollowingSibling:
1639 * @ctxt: the XPath Parser context
1640 * @cur: the current node in the traversal
1641 *
1642 * Traversal function for the "following-sibling" direction
1643 * The following-sibling axis contains the following siblings of the context
1644 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001645 *
1646 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001647 */
1648xmlNodePtr
1649xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001650 if (cur == (xmlNodePtr) ctxt->context->doc)
1651 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001652 if (cur == NULL)
1653 return(ctxt->context->node->next);
1654 return(cur->next);
1655}
1656
1657/**
1658 * xmlXPathNextPrecedingSibling:
1659 * @ctxt: the XPath Parser context
1660 * @cur: the current node in the traversal
1661 *
1662 * Traversal function for the "preceding-sibling" direction
1663 * The preceding-sibling axis contains the preceding siblings of the context
1664 * node in reverse document order; the first preceding sibling is first on the
1665 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001666 *
1667 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001668 */
1669xmlNodePtr
1670xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001671 if (cur == (xmlNodePtr) ctxt->context->doc)
1672 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001673 if (cur == NULL)
1674 return(ctxt->context->node->prev);
1675 return(cur->prev);
1676}
1677
1678/**
1679 * xmlXPathNextFollowing:
1680 * @ctxt: the XPath Parser context
1681 * @cur: the current node in the traversal
1682 *
1683 * Traversal function for the "following" direction
1684 * The following axis contains all nodes in the same document as the context
1685 * node that are after the context node in document order, excluding any
1686 * descendants and excluding attribute nodes and namespace nodes; the nodes
1687 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001688 *
1689 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001690 */
1691xmlNodePtr
1692xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001693 if (cur == (xmlNodePtr) ctxt->context->doc)
1694 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001695 if (cur == NULL)
1696 return(ctxt->context->node->next);; /* !!!!!!!!! */
1697 if (cur->childs != NULL) return(cur->childs);
1698 if (cur->next != NULL) return(cur->next);
1699
1700 do {
1701 cur = cur->parent;
1702 if (cur == NULL) return(NULL);
1703 if (cur == ctxt->context->doc->root) return(NULL);
1704 if (cur->next != NULL) {
1705 cur = cur->next;
1706 return(cur);
1707 }
1708 } while (cur != NULL);
1709 return(cur);
1710}
1711
1712/**
1713 * xmlXPathNextPreceding:
1714 * @ctxt: the XPath Parser context
1715 * @cur: the current node in the traversal
1716 *
1717 * Traversal function for the "preceding" direction
1718 * the preceding axis contains all nodes in the same document as the context
1719 * node that are before the context node in document order, excluding any
1720 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1721 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001722 *
1723 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001724 */
1725xmlNodePtr
1726xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001727 if (cur == (xmlNodePtr) ctxt->context->doc)
1728 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001729 if (cur == NULL)
1730 return(ctxt->context->node->prev); /* !!!!!!!!! */
1731 if (cur->last != NULL) return(cur->last);
1732 if (cur->prev != NULL) return(cur->prev);
1733
1734 do {
1735 cur = cur->parent;
1736 if (cur == NULL) return(NULL);
1737 if (cur == ctxt->context->doc->root) return(NULL);
1738 if (cur->prev != NULL) {
1739 cur = cur->prev;
1740 return(cur);
1741 }
1742 } while (cur != NULL);
1743 return(cur);
1744}
1745
1746/**
1747 * xmlXPathNextNamespace:
1748 * @ctxt: the XPath Parser context
1749 * @cur: the current attribute in the traversal
1750 *
1751 * Traversal function for the "namespace" direction
1752 * the namespace axis contains the namespace nodes of the context node;
1753 * the order of nodes on this axis is implementation-defined; the axis will
1754 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001755 *
1756 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001757 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001758xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001759xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001760 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1761 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001762 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001763 ctxt->context->namespaces =
1764 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1765 if (ctxt->context->namespaces == NULL) return(NULL);
1766 ctxt->context->nsNr = 0;
1767 }
1768 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001769}
1770
1771/**
1772 * xmlXPathNextAttribute:
1773 * @ctxt: the XPath Parser context
1774 * @cur: the current attribute in the traversal
1775 *
1776 * Traversal function for the "attribute" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001777 *
1778 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001779 */
1780xmlAttrPtr
1781xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001782 if (cur == NULL) {
1783 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1784 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001785 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001786 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001787 return(cur->next);
1788}
1789
1790/************************************************************************
1791 * *
1792 * NodeTest Functions *
1793 * *
1794 ************************************************************************/
1795
1796#define NODE_TEST_NONE 0
1797#define NODE_TEST_TYPE 1
1798#define NODE_TEST_PI 2
1799#define NODE_TEST_ALL 3
1800#define NODE_TEST_NS 4
1801#define NODE_TEST_NAME 5
1802
1803#define NODE_TYPE_COMMENT 50
1804#define NODE_TYPE_TEXT 51
1805#define NODE_TYPE_PI 52
1806#define NODE_TYPE_NODE 53
1807
1808#define IS_FUNCTION 200
1809
1810/**
1811 * xmlXPathNodeCollectAndTest:
1812 * @ctxt: the XPath Parser context
1813 * @cur: the current node to test
1814 *
1815 * This is the function implementing a step: based on the current list
1816 * of nodes, it builds up a new list, looking at all nodes under that
1817 * axis and selecting them.
1818 *
1819 * Returns the new NodeSet resulting from the search.
1820 */
1821xmlNodeSetPtr
1822xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
1823 int test, int type, const CHAR *prefix, const CHAR *name) {
1824#ifdef DEBUG_STEP
1825 int n = 0, t = 0;
1826#endif
1827 int i;
1828 xmlNodeSetPtr ret;
1829 xmlXPathTraversalFunction next = NULL;
1830 xmlNodePtr cur = NULL;
1831
1832 if (ctxt->context->nodelist == NULL) {
1833 if (ctxt->context->node == NULL) {
1834 fprintf(xmlXPathDebug,
1835 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1836 __FILE__, __LINE__);
1837 return(NULL);
1838 }
1839 STRANGE
1840 return(NULL);
1841 }
1842#ifdef DEBUG_STEP
1843 fprintf(xmlXPathDebug, "new step : ");
1844#endif
1845 switch (axis) {
1846 case AXIS_ANCESTOR:
1847#ifdef DEBUG_STEP
1848 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1849#endif
1850 next = xmlXPathNextAncestor; break;
1851 case AXIS_ANCESTOR_OR_SELF:
1852#ifdef DEBUG_STEP
1853 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1854#endif
1855 next = xmlXPathNextAncestorOrSelf; break;
1856 case AXIS_ATTRIBUTE:
1857#ifdef DEBUG_STEP
1858 fprintf(xmlXPathDebug, "axis 'attributes' ");
1859#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001860 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001861 break;
1862 case AXIS_CHILD:
1863#ifdef DEBUG_STEP
1864 fprintf(xmlXPathDebug, "axis 'child' ");
1865#endif
1866 next = xmlXPathNextChild; break;
1867 case AXIS_DESCENDANT:
1868#ifdef DEBUG_STEP
1869 fprintf(xmlXPathDebug, "axis 'descendant' ");
1870#endif
1871 next = xmlXPathNextDescendant; break;
1872 case AXIS_DESCENDANT_OR_SELF:
1873#ifdef DEBUG_STEP
1874 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1875#endif
1876 next = xmlXPathNextDescendantOrSelf; break;
1877 case AXIS_FOLLOWING:
1878#ifdef DEBUG_STEP
1879 fprintf(xmlXPathDebug, "axis 'following' ");
1880#endif
1881 next = xmlXPathNextFollowing; break;
1882 case AXIS_FOLLOWING_SIBLING:
1883#ifdef DEBUG_STEP
1884 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1885#endif
1886 next = xmlXPathNextFollowingSibling; break;
1887 case AXIS_NAMESPACE:
1888#ifdef DEBUG_STEP
1889 fprintf(xmlXPathDebug, "axis 'namespace' ");
1890#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001891 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001892 break;
1893 case AXIS_PARENT:
1894#ifdef DEBUG_STEP
1895 fprintf(xmlXPathDebug, "axis 'parent' ");
1896#endif
1897 next = xmlXPathNextParent; break;
1898 case AXIS_PRECEDING:
1899#ifdef DEBUG_STEP
1900 fprintf(xmlXPathDebug, "axis 'preceding' ");
1901#endif
1902 next = xmlXPathNextPreceding; break;
1903 case AXIS_PRECEDING_SIBLING:
1904#ifdef DEBUG_STEP
1905 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1906#endif
1907 next = xmlXPathNextPrecedingSibling; break;
1908 case AXIS_SELF:
1909#ifdef DEBUG_STEP
1910 fprintf(xmlXPathDebug, "axis 'self' ");
1911#endif
1912 next = xmlXPathNextSelf; break;
1913 }
1914 if (next == NULL) return(NULL);
1915 ret = xmlXPathNodeSetCreate(NULL);
1916#ifdef DEBUG_STEP
1917 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1918 ctxt->context->nodelist->nodeNr);
1919 switch (test) {
1920 case NODE_TEST_NONE:
1921 fprintf(xmlXPathDebug, " seaching for none !!!\n");
1922 break;
1923 case NODE_TEST_TYPE:
1924 fprintf(xmlXPathDebug, " seaching for type %d\n", type);
1925 break;
1926 case NODE_TEST_PI:
1927 fprintf(xmlXPathDebug, " seaching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001928 break;
1929 case NODE_TEST_ALL:
1930 fprintf(xmlXPathDebug, " seaching for *\n");
1931 break;
1932 case NODE_TEST_NS:
1933 fprintf(xmlXPathDebug, " seaching for namespace %s\n",
1934 prefix);
1935 break;
1936 case NODE_TEST_NAME:
1937 fprintf(xmlXPathDebug, " seaching for name %s\n", name);
1938 if (prefix != NULL)
1939 fprintf(xmlXPathDebug, " with namespace %s\n",
1940 prefix);
1941 break;
1942 }
1943 fprintf(xmlXPathDebug, "Testing : ");
1944#endif
1945 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1946 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1947
1948 cur = NULL;
1949 do {
1950 cur = next(ctxt, cur);
1951 if (cur == NULL) break;
1952#ifdef DEBUG_STEP
1953 t++;
1954 fprintf(xmlXPathDebug, " %s", cur->name);
1955#endif
1956 switch (test) {
1957 case NODE_TEST_NONE:
1958 STRANGE
1959 return(NULL);
1960 case NODE_TEST_TYPE:
1961 if (cur->type == type) {
1962#ifdef DEBUG_STEP
1963 n++;
1964#endif
1965 xmlXPathNodeSetAdd(ret, cur);
1966 }
1967 break;
1968 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001969 if (cur->type == XML_PI_NODE) {
1970 if ((name != NULL) &&
1971 (xmlStrcmp(name, cur->name)))
1972 break;
1973#ifdef DEBUG_STEP
1974 n++;
1975#endif
1976 xmlXPathNodeSetAdd(ret, cur);
1977 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001978 break;
1979 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001980 if ((cur->type == XML_ELEMENT_NODE) ||
1981 (cur->type == XML_ATTRIBUTE_NODE)) {
1982 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001983#ifdef DEBUG_STEP
1984 n++;
1985#endif
1986 xmlXPathNodeSetAdd(ret, cur);
1987 }
1988 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001989 case NODE_TEST_NS: {
1990 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001991 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001992 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001993 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001994 switch (cur->type) {
1995 case XML_ELEMENT_NODE:
1996 if (!xmlStrcmp(name, cur->name) &&
1997 (((prefix == NULL) ||
1998 ((cur->ns != NULL) &&
1999 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002000#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002001 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002002#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002003 xmlXPathNodeSetAdd(ret, cur);
2004 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002005 break;
2006 case XML_ATTRIBUTE_NODE: {
2007 xmlAttrPtr attr = (xmlAttrPtr) cur;
2008 if (!xmlStrcmp(name, attr->name)) {
2009#ifdef DEBUG_STEP
2010 n++;
2011#endif
2012 xmlXPathNodeSetAdd(ret, cur);
2013 }
2014 break;
2015 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002016 default:
2017 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002018 }
2019 break;
2020
2021 }
2022 } while (cur != NULL);
2023 }
2024#ifdef DEBUG_STEP
2025 fprintf(xmlXPathDebug,
2026 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2027#endif
2028 return(ret);
2029}
2030
2031
2032/************************************************************************
2033 * *
2034 * Implicit tree core function library *
2035 * *
2036 ************************************************************************/
2037
2038/**
2039 * xmlXPathRoot:
2040 * @ctxt: the XPath Parser context
2041 *
2042 * Initialize the context to the root of the document
2043 */
2044void
2045xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2046 if (ctxt->context->nodelist != NULL)
2047 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002048 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2049 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002050}
2051
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002052/************************************************************************
2053 * *
2054 * The explicit core function library *
2055 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2056 * *
2057 ************************************************************************/
2058
2059
2060/**
2061 * xmlXPathLastFunction:
2062 * @ctxt: the XPath Parser context
2063 *
2064 * Implement the last() XPath function
2065 * The last function returns the number of nodes in the context node list.
2066 */
2067void
2068xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2069 CHECK_ARITY(0);
2070 if ((ctxt->context->nodelist == NULL) ||
2071 (ctxt->context->node == NULL) ||
2072 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002073 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002074 } else {
2075 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002076 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002077 }
2078}
2079
2080/**
2081 * xmlXPathPositionFunction:
2082 * @ctxt: the XPath Parser context
2083 *
2084 * Implement the position() XPath function
2085 * The position function returns the position of the context node in the
2086 * context node list. The first position is 1, and so the last positionr
2087 * will be equal to last().
2088 */
2089void
2090xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2091 int i;
2092
2093 CHECK_ARITY(0);
2094 if ((ctxt->context->nodelist == NULL) ||
2095 (ctxt->context->node == NULL) ||
2096 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002097 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002098 }
2099 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2100 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002101 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002102 return;
2103 }
2104 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002105 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002106}
2107
2108/**
2109 * xmlXPathCountFunction:
2110 * @ctxt: the XPath Parser context
2111 *
2112 * Implement the count() XPath function
2113 */
2114void
2115xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2116 xmlXPathObjectPtr cur;
2117
2118 CHECK_ARITY(1);
2119 CHECK_TYPE(XPATH_NODESET);
2120 cur = valuePop(ctxt);
2121
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002122 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002123 xmlXPathFreeObject(cur);
2124}
2125
2126/**
2127 * xmlXPathIdFunction:
2128 * @ctxt: the XPath Parser context
2129 *
2130 * Implement the id() XPath function
2131 * The id function selects elements by their unique ID
2132 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2133 * then the result is the union of the result of applying id to the
2134 * string value of each of the nodes in the argument node-set. When the
2135 * argument to id is of any other type, the argument is converted to a
2136 * string as if by a call to the string function; the string is split
2137 * into a whitespace-separated list of tokens (whitespace is any sequence
2138 * of characters matching the production S); the result is a node-set
2139 * containing the elements in the same document as the context node that
2140 * have a unique ID equal to any of the tokens in the list.
2141 */
2142void
2143xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002144 const CHAR *tokens;
2145 const CHAR *cur;
2146 CHAR *ID;
2147 xmlAttrPtr attr;
2148 xmlNodePtr elem = NULL;
2149 xmlXPathObjectPtr ret, obj;
2150
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002151 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002152 obj = valuePop(ctxt);
2153 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2154 if (obj->type == XPATH_NODESET) {
2155 TODO /* ID function in case of NodeSet */
2156 }
2157 if (obj->type != XPATH_STRING) {
2158 valuePush(ctxt, obj);
2159 xmlXPathStringFunction(ctxt, 1);
2160 obj = valuePop(ctxt);
2161 if (obj->type != XPATH_STRING) {
2162 xmlXPathFreeObject(obj);
2163 return;
2164 }
2165 }
2166 tokens = obj->stringval;
2167
2168 ret = xmlXPathNewNodeSet(NULL);
2169 valuePush(ctxt, ret);
2170 if (tokens == NULL) {
2171 xmlXPathFreeObject(obj);
2172 return;
2173 }
2174
2175 cur = tokens;
2176
2177 while (IS_BLANK(*cur)) cur++;
2178 while (*cur != 0) {
2179 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2180 (*cur == '.') || (*cur == '-') ||
2181 (*cur == '_') || (*cur == ':') ||
2182 (IS_COMBINING(*cur)) ||
2183 (IS_EXTENDER(*cur)))
2184 cur++;
2185
2186 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2187
2188 ID = xmlStrndup(tokens, cur - tokens);
2189 attr = xmlGetID(ctxt->context->doc, ID);
2190 if (attr != NULL) {
2191 elem = attr->node;
2192 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2193 }
2194 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002195 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002196
2197 while (IS_BLANK(*cur)) cur++;
2198 tokens = cur;
2199 }
2200 xmlXPathFreeObject(obj);
2201 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002202}
2203
2204/**
2205 * xmlXPathLocalPartFunction:
2206 * @ctxt: the XPath Parser context
2207 *
2208 * Implement the local-part() XPath function
2209 * The local-part function returns a string containing the local part
2210 * of the name of the node in the argument node-set that is first in
2211 * document order. If the node-set is empty or the first node has no
2212 * name, an empty string is returned. If the argument is omitted it
2213 * defaults to the context node.
2214 */
2215void
2216xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2217 xmlXPathObjectPtr cur;
2218
2219 CHECK_ARITY(1);
2220 CHECK_TYPE(XPATH_NODESET);
2221 cur = valuePop(ctxt);
2222
2223 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002224 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002225 } else {
2226 int i = 0; /* Should be first in document order !!!!! */
2227 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2228 }
2229 xmlXPathFreeObject(cur);
2230}
2231
2232/**
2233 * xmlXPathNamespaceFunction:
2234 * @ctxt: the XPath Parser context
2235 *
2236 * Implement the namespace() XPath function
2237 * The namespace function returns a string containing the namespace URI
2238 * of the expanded name of the node in the argument node-set that is
2239 * first in document order. If the node-set is empty, the first node has
2240 * no name, or the expanded name has no namespace URI, an empty string
2241 * is returned. If the argument is omitted it defaults to the context node.
2242 */
2243void
2244xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2245 xmlXPathObjectPtr cur;
2246
Daniel Veillardb96e6431999-08-29 21:02:19 +00002247 if (nargs == 0) {
2248 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2249 nargs = 1;
2250 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002251 CHECK_ARITY(1);
2252 CHECK_TYPE(XPATH_NODESET);
2253 cur = valuePop(ctxt);
2254
2255 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002256 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002257 } else {
2258 int i = 0; /* Should be first in document order !!!!! */
2259
2260 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002261 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002262 else
2263 valuePush(ctxt, xmlXPathNewString(
2264 cur->nodesetval->nodeTab[i]->ns->href));
2265 }
2266 xmlXPathFreeObject(cur);
2267}
2268
2269/**
2270 * xmlXPathNameFunction:
2271 * @ctxt: the XPath Parser context
2272 *
2273 * Implement the name() XPath function
2274 * The name function returns a string containing a QName representing
2275 * the name of the node in the argument node-set that is first in documenti
2276 * order. The QName must represent the name with respect to the namespace
2277 * declarations in effect on the node whose name is being represented.
2278 * Typically, this will be the form in which the name occurred in the XML
2279 * source. This need not be the case if there are namespace declarations
2280 * in effect on the node that associate multiple prefixes with the same
2281 * namespace. However, an implementation may include information about
2282 * the original prefix in its representation of nodes; in this case, an
2283 * implementation can ensure that the returned string is always the same
2284 * as the QName used in the XML source. If the argument it omitted it
2285 * defaults to the context node.
2286 * Libxml keep the original prefix so the "real qualified name" used is
2287 * returned.
2288 */
2289void
2290xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2291 xmlXPathObjectPtr cur;
2292
2293 CHECK_ARITY(1);
2294 CHECK_TYPE(XPATH_NODESET);
2295 cur = valuePop(ctxt);
2296
2297 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002298 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002299 } else {
2300 int i = 0; /* Should be first in document order !!!!! */
2301
2302 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2303 valuePush(ctxt, xmlXPathNewString(
2304 cur->nodesetval->nodeTab[i]->name));
2305
2306 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002307 char name[2000];
2308 sprintf(name, "%s:%s",
2309 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2310 (char *) cur->nodesetval->nodeTab[i]->name);
2311 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002312 }
2313 }
2314 xmlXPathFreeObject(cur);
2315}
2316
2317/**
2318 * xmlXPathStringFunction:
2319 * @ctxt: the XPath Parser context
2320 *
2321 * Implement the string() XPath function
2322 * he string function converts an object to a string as follows:
2323 * - A node-set is converted to a string by returning the value of
2324 * the node in the node-set that is first in document order.
2325 * If the node-set is empty, an empty string is returned.
2326 * - A number is converted to a string as follows
2327 * + NaN is converted to the string NaN
2328 * + positive zero is converted to the string 0
2329 * + negative zero is converted to the string 0
2330 * + positive infinity is converted to the string Infinity
2331 * + negative infinity is converted to the string -Infinity
2332 * + if the number is an integer, the number is represented in
2333 * decimal form as a Number with no decimal point and no leading
2334 * zeros, preceded by a minus sign (-) if the number is negative
2335 * + otherwise, the number is represented in decimal form as a
2336 * Number including a decimal point with at least one digit
2337 * before the decimal point and at least one digit after the
2338 * decimal point, preceded by a minus sign (-) if the number
2339 * is negative; there must be no leading zeros before the decimal
2340 * point apart possibly from the one required digit immediatelyi
2341 * before the decimal point; beyond the one required digit
2342 * after the decimal point there must be as many, but only as
2343 * many, more digits as are needed to uniquely distinguish the
2344 * number from all other IEEE 754 numeric values.
2345 * - The boolean false value is converted to the string false.
2346 * The boolean true value is converted to the string true.
2347 */
2348void
2349xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2350 xmlXPathObjectPtr cur;
2351
2352 CHECK_ARITY(1);
2353 cur = valuePop(ctxt);
2354 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2355 switch (cur->type) {
2356 case XPATH_NODESET:
2357 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002358 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002359 } else {
2360 CHAR *res;
2361 int i = 0; /* Should be first in document order !!!!! */
2362 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2363 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002364 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002365 }
2366 xmlXPathFreeObject(cur);
2367 return;
2368 case XPATH_STRING:
2369 valuePush(ctxt, cur);
2370 return;
2371 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002372 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2373 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002374 xmlXPathFreeObject(cur);
2375 return;
2376 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002377 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002378
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002379 if (isnan(cur->floatval))
2380 sprintf(buf, "NaN");
2381 else if (isinf(cur->floatval) > 0)
2382 sprintf(buf, "+Infinity");
2383 else if (isinf(cur->floatval) < 0)
2384 sprintf(buf, "-Infinity");
2385 else
2386 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002387 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002388 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002389 return;
2390 }
2391 }
2392 STRANGE
2393}
2394
2395/**
2396 * xmlXPathStringLengthFunction:
2397 * @ctxt: the XPath Parser context
2398 *
2399 * Implement the string-length() XPath function
2400 * The string-length returns the number of characters in the string
2401 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2402 * the context node converted to a string, in other words the value
2403 * of the context node.
2404 */
2405void
2406xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2407 xmlXPathObjectPtr cur;
2408
2409 if (nargs == 0) {
2410 if (ctxt->context->node == NULL) {
2411 valuePush(ctxt, xmlXPathNewFloat(0));
2412 } else {
2413 CHAR *content;
2414
2415 content = xmlNodeGetContent(ctxt->context->node);
2416 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002417 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002418 }
2419 return;
2420 }
2421 CHECK_ARITY(1);
2422 CHECK_TYPE(XPATH_STRING);
2423 cur = valuePop(ctxt);
2424 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2425 xmlXPathFreeObject(cur);
2426}
2427
2428/**
2429 * xmlXPathConcatFunction:
2430 * @ctxt: the XPath Parser context
2431 *
2432 * Implement the concat() XPath function
2433 * The concat function returns the concatenation of its arguments.
2434 */
2435void
2436xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2437 xmlXPathObjectPtr cur, new;
2438 CHAR *tmp;
2439
2440 if (nargs < 2) {
2441 CHECK_ARITY(2);
2442 }
2443
2444 cur = valuePop(ctxt);
2445 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2446 xmlXPathFreeObject(cur);
2447 return;
2448 }
2449 nargs--;
2450
2451 while (nargs > 0) {
2452 new = valuePop(ctxt);
2453 if ((new == NULL) || (new->type != XPATH_STRING)) {
2454 xmlXPathFreeObject(new);
2455 xmlXPathFreeObject(cur);
2456 ERROR(XPATH_INVALID_TYPE);
2457 }
2458 tmp = xmlStrcat(new->stringval, cur->stringval);
2459 new->stringval = cur->stringval;
2460 cur->stringval = tmp;
2461
2462 xmlXPathFreeObject(new);
2463 nargs--;
2464 }
2465 valuePush(ctxt, cur);
2466}
2467
2468/**
2469 * xmlXPathContainsFunction:
2470 * @ctxt: the XPath Parser context
2471 *
2472 * Implement the contains() XPath function
2473 * The contains function returns true if the first argument string
2474 * contains the second argument string, and otherwise returns false.
2475 */
2476void
2477xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2478 xmlXPathObjectPtr hay, needle;
2479
2480 CHECK_ARITY(2);
2481 CHECK_TYPE(XPATH_STRING);
2482 needle = valuePop(ctxt);
2483 hay = valuePop(ctxt);
2484 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2485 xmlXPathFreeObject(hay);
2486 xmlXPathFreeObject(needle);
2487 ERROR(XPATH_INVALID_TYPE);
2488 }
2489 if (xmlStrstr(hay->stringval, needle->stringval))
2490 valuePush(ctxt, xmlXPathNewBoolean(1));
2491 else
2492 valuePush(ctxt, xmlXPathNewBoolean(0));
2493 xmlXPathFreeObject(hay);
2494 xmlXPathFreeObject(needle);
2495}
2496
2497/**
2498 * xmlXPathStartsWithFunction:
2499 * @ctxt: the XPath Parser context
2500 *
2501 * Implement the starts-with() XPath function
2502 * The starts-with function returns true if the first argument string
2503 * starts with the second argument string, and otherwise returns false.
2504 */
2505void
2506xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2507 xmlXPathObjectPtr hay, needle;
2508 int n;
2509
2510 CHECK_ARITY(2);
2511 CHECK_TYPE(XPATH_STRING);
2512 needle = valuePop(ctxt);
2513 hay = valuePop(ctxt);
2514 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2515 xmlXPathFreeObject(hay);
2516 xmlXPathFreeObject(needle);
2517 ERROR(XPATH_INVALID_TYPE);
2518 }
2519 n = xmlStrlen(needle->stringval);
2520 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2521 valuePush(ctxt, xmlXPathNewBoolean(0));
2522 else
2523 valuePush(ctxt, xmlXPathNewBoolean(1));
2524 xmlXPathFreeObject(hay);
2525 xmlXPathFreeObject(needle);
2526}
2527
2528/**
2529 * xmlXPathSubstringFunction:
2530 * @ctxt: the XPath Parser context
2531 *
2532 * Implement the substring() XPath function
2533 * The substring function returns the substring of the first argument
2534 * starting at the position specified in the second argument with
2535 * length specified in the third argument. For example,
2536 * substring("12345",2,3) returns "234". If the third argument is not
2537 * specified, it returns the substring starting at the position specified
2538 * in the second argument and continuing to the end of the string. For
2539 * example, substring("12345",2) returns "2345". More precisely, each
2540 * character in the string (see [3.6 Strings]) is considered to have a
2541 * numeric position: the position of the first character is 1, the position
2542 * of the second character is 2 and so on. The returned substring contains
2543 * those characters for which the position of the character is greater than
2544 * or equal to the second argument and, if the third argument is specified,
2545 * less than the sum of the second and third arguments; the comparisons
2546 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2547 * - substring("12345", 1.5, 2.6) returns "234"
2548 * - substring("12345", 0, 3) returns "12"
2549 * - substring("12345", 0 div 0, 3) returns ""
2550 * - substring("12345", 1, 0 div 0) returns ""
2551 * - substring("12345", -42, 1 div 0) returns "12345"
2552 * - substring("12345", -1 div 0, 1 div 0) returns ""
2553 */
2554void
2555xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2556 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002557 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002558 int i, l;
2559 CHAR *ret;
2560
2561 /*
2562 * Conformance needs to be checked !!!!!
2563 */
2564 if (nargs < 2) {
2565 CHECK_ARITY(2);
2566 }
2567 if (nargs > 3) {
2568 CHECK_ARITY(3);
2569 }
2570 if (nargs == 3) {
2571 CHECK_TYPE(XPATH_NUMBER);
2572 len = valuePop(ctxt);
2573 le = len->floatval;
2574 xmlXPathFreeObject(len);
2575 } else {
2576 le = 2000000000;
2577 }
2578 CHECK_TYPE(XPATH_NUMBER);
2579 start = valuePop(ctxt);
2580 in = start->floatval;
2581 xmlXPathFreeObject(start);
2582 CHECK_TYPE(XPATH_STRING);
2583 str = valuePop(ctxt);
2584 le += in;
2585
2586 /* integer index of the first char */
2587 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002588 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002589
2590 /* integer index of the last char */
2591 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002592 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002593
2594 /* back to a zero based len */
2595 i--;
2596 l--;
2597
2598 /* check against the string len */
2599 if (l > 1024) {
2600 l = xmlStrlen(str->stringval);
2601 }
2602 if (i < 0) {
2603 i = 0;
2604 }
2605
2606 /* number of chars to copy */
2607 l -= i;
2608
2609 ret = xmlStrsub(str->stringval, i, l);
2610 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002611 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002612 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002613 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002614 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002615 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002616 xmlXPathFreeObject(str);
2617}
2618
2619/**
2620 * xmlXPathSubstringBeforeFunction:
2621 * @ctxt: the XPath Parser context
2622 *
2623 * Implement the substring-before() XPath function
2624 * The substring-before function returns the substring of the first
2625 * argument string that precedes the first occurrence of the second
2626 * argument string in the first argument string, or the empty string
2627 * if the first argument string does not contain the second argument
2628 * string. For example, substring-before("1999/04/01","/") returns 1999.
2629 */
2630void
2631xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2632 CHECK_ARITY(2);
2633 TODO /* substring before */
2634}
2635
2636/**
2637 * xmlXPathSubstringAfterFunction:
2638 * @ctxt: the XPath Parser context
2639 *
2640 * Implement the substring-after() XPath function
2641 * The substring-after function returns the substring of the first
2642 * argument string that follows the first occurrence of the second
2643 * argument string in the first argument string, or the empty stringi
2644 * if the first argument string does not contain the second argument
2645 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2646 * and substring-after("1999/04/01","19") returns 99/04/01.
2647 */
2648void
2649xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2650 CHECK_ARITY(2);
2651 TODO /* substring after */
2652}
2653
2654/**
2655 * xmlXPathNormalizeFunction:
2656 * @ctxt: the XPath Parser context
2657 *
2658 * Implement the normalize() XPath function
2659 * The normalize function returns the argument string with white
2660 * space normalized by stripping leading and trailing whitespace
2661 * and replacing sequences of whitespace characters by a single
2662 * space. Whitespace characters are the same allowed by the S production
2663 * in XML. If the argument is omitted, it defaults to the context
2664 * node converted to a string, in other words the value of the context node.
2665 */
2666void
2667xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2668 CHECK_ARITY(1);
2669 TODO /* normalize isn't as boring as translate, but pretty much */
2670}
2671
2672/**
2673 * xmlXPathTranslateFunction:
2674 * @ctxt: the XPath Parser context
2675 *
2676 * Implement the translate() XPath function
2677 * The translate function returns the first argument string with
2678 * occurrences of characters in the second argument string replaced
2679 * by the character at the corresponding position in the third argument
2680 * string. For example, translate("bar","abc","ABC") returns the string
2681 * BAr. If there is a character in the second argument string with no
2682 * character at a corresponding position in the third argument string
2683 * (because the second argument string is longer than the third argument
2684 * string), then occurrences of that character in the first argument
2685 * string are removed. For example, translate("--aaa--","abc-","ABC")
2686 * returns "AAA". If a character occurs more than once in second
2687 * argument string, then the first occurrence determines the replacement
2688 * character. If the third argument string is longer than the second
2689 * argument string, then excess characters are ignored.
2690 */
2691void
2692xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2693 CHECK_ARITY(3);
2694 TODO /* translate is boring, waiting for UTF-8 representation too */
2695}
2696
2697/**
2698 * xmlXPathBooleanFunction:
2699 * @ctxt: the XPath Parser context
2700 *
2701 * Implement the boolean() XPath function
2702 * he boolean function converts its argument to a boolean as follows:
2703 * - a number is true if and only if it is neither positive or
2704 * negative zero nor NaN
2705 * - a node-set is true if and only if it is non-empty
2706 * - a string is true if and only if its length is non-zero
2707 */
2708void
2709xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2710 xmlXPathObjectPtr cur;
2711 int res = 0;
2712
2713 CHECK_ARITY(1);
2714 cur = valuePop(ctxt);
2715 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2716 switch (cur->type) {
2717 case XPATH_NODESET:
2718 if ((cur->nodesetval == NULL) ||
2719 (cur->nodesetval->nodeNr == 0)) res = 0;
2720 else
2721 res = 1;
2722 break;
2723 case XPATH_STRING:
2724 if ((cur->stringval == NULL) ||
2725 (cur->stringval[0] == 0)) res = 0;
2726 else
2727 res = 1;
2728 break;
2729 case XPATH_BOOLEAN:
2730 valuePush(ctxt, cur);
2731 return;
2732 case XPATH_NUMBER:
2733 if (cur->floatval) res = 1;
2734 break;
2735 default:
2736 STRANGE
2737 }
2738 xmlXPathFreeObject(cur);
2739 valuePush(ctxt, xmlXPathNewBoolean(res));
2740}
2741
2742/**
2743 * xmlXPathNotFunction:
2744 * @ctxt: the XPath Parser context
2745 *
2746 * Implement the not() XPath function
2747 * The not function returns true if its argument is false,
2748 * and false otherwise.
2749 */
2750void
2751xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2752 CHECK_ARITY(1);
2753 CHECK_TYPE(XPATH_BOOLEAN);
2754 ctxt->value->boolval = ! ctxt->value->boolval;
2755}
2756
2757/**
2758 * xmlXPathTrueFunction:
2759 * @ctxt: the XPath Parser context
2760 *
2761 * Implement the true() XPath function
2762 */
2763void
2764xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2765 CHECK_ARITY(0);
2766 valuePush(ctxt, xmlXPathNewBoolean(1));
2767}
2768
2769/**
2770 * xmlXPathFalseFunction:
2771 * @ctxt: the XPath Parser context
2772 *
2773 * Implement the false() XPath function
2774 */
2775void
2776xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2777 CHECK_ARITY(0);
2778 valuePush(ctxt, xmlXPathNewBoolean(0));
2779}
2780
2781/**
2782 * xmlXPathLangFunction:
2783 * @ctxt: the XPath Parser context
2784 *
2785 * Implement the lang() XPath function
2786 * The lang function returns true or false depending on whether the
2787 * language of the context node as specified by xml:lang attributes
2788 * is the same as or is a sublanguage of the language specified by
2789 * the argument string. The language of the context node is determined
2790 * by the value of the xml:lang attribute on the context node, or, if
2791 * the context node has no xml:lang attribute, by the value of the
2792 * xml:lang attribute on the nearest ancestor of the context node that
2793 * has an xml:lang attribute. If there is no such attribute, then lang
2794 * returns false. If there is such an attribute, then lang returns
2795 * true if the attribute value is equal to the argument ignoring case,
2796 * or if there is some suffix starting with - such that the attribute
2797 * value is equal to the argument ignoring that suffix of the attribute
2798 * value and ignoring case.
2799 */
2800void
2801xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002802 xmlXPathObjectPtr val;
2803 const CHAR *theLang;
2804 const CHAR *lang;
2805 int ret = 0;
2806 int i;
2807
2808 CHECK_ARITY(1);
2809 CHECK_TYPE(XPATH_STRING);
2810 val = valuePop(ctxt);
2811 lang = val->stringval;
2812 theLang = xmlNodeGetLang(ctxt->context->node);
2813 if ((theLang != NULL) && (lang != NULL)) {
2814 for (i = 0;lang[i] != 0;i++)
2815 if (toupper(lang[i]) != toupper(theLang[i]))
2816 goto not_equal;
2817 ret = 1;
2818 }
2819not_equal:
2820 xmlXPathFreeObject(val);
2821 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002822}
2823
2824/**
2825 * xmlXPathNumberFunction:
2826 * @ctxt: the XPath Parser context
2827 *
2828 * Implement the number() XPath function
2829 */
2830void
2831xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2832 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002833 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002834
2835 CHECK_ARITY(1);
2836 cur = valuePop(ctxt);
2837 switch (cur->type) {
2838 case XPATH_NODESET:
2839 valuePush(ctxt, cur);
2840 xmlXPathStringFunction(ctxt, 1);
2841 cur = valuePop(ctxt);
2842 case XPATH_STRING:
2843 res = xmlXPathStringEvalNumber(cur->stringval);
2844 valuePush(ctxt, xmlXPathNewFloat(res));
2845 xmlXPathFreeObject(cur);
2846 return;
2847 case XPATH_BOOLEAN:
2848 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2849 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2850 xmlXPathFreeObject(cur);
2851 return;
2852 case XPATH_NUMBER:
2853 valuePush(ctxt, cur);
2854 return;
2855 }
2856 STRANGE
2857}
2858
2859/**
2860 * xmlXPathSumFunction:
2861 * @ctxt: the XPath Parser context
2862 *
2863 * Implement the sum() XPath function
2864 * The sum function returns the sum of the values of the nodes in
2865 * the argument node-set.
2866 */
2867void
2868xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2869 CHECK_ARITY(1);
2870 TODO /* BUG Sum : don't understand the definition */
2871}
2872
2873/**
2874 * xmlXPathFloorFunction:
2875 * @ctxt: the XPath Parser context
2876 *
2877 * Implement the floor() XPath function
2878 * The floor function returns the largest (closest to positive infinity)
2879 * number that is not greater than the argument and that is an integer.
2880 */
2881void
2882xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2883 CHECK_ARITY(1);
2884 CHECK_TYPE(XPATH_NUMBER);
2885 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002886 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002887}
2888
2889/**
2890 * xmlXPathCeilingFunction:
2891 * @ctxt: the XPath Parser context
2892 *
2893 * Implement the ceiling() XPath function
2894 * The ceiling function returns the smallest (closest to negative infinity)
2895 * number that is not less than the argument and that is an integer.
2896 */
2897void
2898xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002899 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002900
2901 CHECK_ARITY(1);
2902 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002903 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002904 if (f != ctxt->value->floatval)
2905 ctxt->value->floatval = f + 1;
2906}
2907
2908/**
2909 * xmlXPathRoundFunction:
2910 * @ctxt: the XPath Parser context
2911 *
2912 * Implement the round() XPath function
2913 * The round function returns the number that is closest to the
2914 * argument and that is an integer. If there are two such numbers,
2915 * then the one that is even is returned.
2916 */
2917void
2918xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002919 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002920
2921 CHECK_ARITY(1);
2922 CHECK_TYPE(XPATH_NUMBER);
2923 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002924 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002925 if (ctxt->value->floatval < f + 0.5)
2926 ctxt->value->floatval = f;
2927 else if (ctxt->value->floatval == f + 0.5)
2928 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2929 else
2930 ctxt->value->floatval = f + 1;
2931}
2932
2933/************************************************************************
2934 * *
2935 * The Parser *
2936 * *
2937 ************************************************************************/
2938
2939/*
2940 * a couple of forward declarations since we use a recursive call based
2941 * implementation.
2942 */
2943void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2944void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2945void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2946void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2947
2948/**
2949 * xmlXPathParseNCName:
2950 * @ctxt: the XPath Parser context
2951 *
2952 * parse an XML namespace non qualified name.
2953 *
2954 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2955 *
2956 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2957 * CombiningChar | Extender
2958 *
2959 * Returns the namespace name or NULL
2960 */
2961
2962CHAR *
2963xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
2964 const CHAR *q;
2965 CHAR *ret = NULL;
2966
2967 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2968 q = NEXT;
2969
2970 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2971 (CUR == '.') || (CUR == '-') ||
2972 (CUR == '_') ||
2973 (IS_COMBINING(CUR)) ||
2974 (IS_EXTENDER(CUR)))
2975 NEXT;
2976
2977 ret = xmlStrndup(q, CUR_PTR - q);
2978
2979 return(ret);
2980}
2981
2982/**
2983 * xmlXPathParseQName:
2984 * @ctxt: the XPath Parser context
2985 * @prefix: a CHAR **
2986 *
2987 * parse an XML qualified name
2988 *
2989 * [NS 5] QName ::= (Prefix ':')? LocalPart
2990 *
2991 * [NS 6] Prefix ::= NCName
2992 *
2993 * [NS 7] LocalPart ::= NCName
2994 *
2995 * Returns the function returns the local part, and prefix is updated
2996 * to get the Prefix if any.
2997 */
2998
2999CHAR *
3000xmlXPathParseQName(xmlXPathParserContextPtr ctxt, CHAR **prefix) {
3001 CHAR *ret = NULL;
3002
3003 *prefix = NULL;
3004 ret = xmlXPathParseNCName(ctxt);
3005 if (CUR == ':') {
3006 *prefix = ret;
3007 NEXT;
3008 ret = xmlXPathParseNCName(ctxt);
3009 }
3010 return(ret);
3011}
3012
3013/**
3014 * xmlXPathStringEvalNumber:
3015 * @str: A string to scan
3016 *
3017 * [30] Number ::= Digits ('.' Digits)?
3018 * | '.' Digits
3019 * [31] Digits ::= [0-9]+
3020 *
3021 * Parse and evaluate a Number in the string
3022 *
3023 * BUG: "1.' is not valid ... James promised correction
3024 * as Digits ('.' Digits?)?
3025 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003026 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003027 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003028double
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003029xmlXPathStringEvalNumber(const CHAR *str) {
3030 const CHAR *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003031 double ret = 0.0;
3032 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003033 int ok = 0;
3034
3035 while (*cur == ' ') cur++;
3036 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003037 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003038 }
3039 while ((*cur >= '0') && (*cur <= '9')) {
3040 ret = ret * 10 + (*cur - '0');
3041 ok = 1;
3042 cur++;
3043 }
3044 if (*cur == '.') {
3045 cur++;
3046 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003047 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003048 }
3049 while ((*cur >= '0') && (*cur <= '9')) {
3050 mult /= 10;
3051 ret = ret + (*cur - '0') * mult;
3052 cur++;
3053 }
3054 }
3055 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003056 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003057 return(ret);
3058}
3059
3060/**
3061 * xmlXPathEvalNumber:
3062 * @ctxt: the XPath Parser context
3063 *
3064 * [30] Number ::= Digits ('.' Digits)?
3065 * | '.' Digits
3066 * [31] Digits ::= [0-9]+
3067 *
3068 * Parse and evaluate a Number, then push it on the stack
3069 *
3070 * BUG: "1.' is not valid ... James promised correction
3071 * as Digits ('.' Digits?)?
3072 */
3073void
3074xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003075 double ret = 0.0;
3076 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003077 int ok = 0;
3078
3079 CHECK_ERROR;
3080 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3081 ERROR(XPATH_NUMBER_ERROR);
3082 }
3083 while ((CUR >= '0') && (CUR <= '9')) {
3084 ret = ret * 10 + (CUR - '0');
3085 ok = 1;
3086 NEXT;
3087 }
3088 if (CUR == '.') {
3089 NEXT;
3090 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3091 ERROR(XPATH_NUMBER_ERROR);
3092 }
3093 while ((CUR >= '0') && (CUR <= '9')) {
3094 mult /= 10;
3095 ret = ret + (CUR - '0') * mult;
3096 NEXT;
3097 }
3098 }
3099 valuePush(ctxt, xmlXPathNewFloat(ret));
3100}
3101
3102/**
3103 * xmlXPathEvalLiteral:
3104 * @ctxt: the XPath Parser context
3105 *
3106 * Parse a Literal and push it on the stack.
3107 *
3108 * [29] Literal ::= '"' [^"]* '"'
3109 * | "'" [^']* "'"
3110 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003111 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003112 */
3113void
3114xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
3115 const CHAR *q;
3116 CHAR *ret = NULL;
3117
3118 if (CUR == '"') {
3119 NEXT;
3120 q = CUR_PTR;
3121 while ((IS_CHAR(CUR)) && (CUR != '"'))
3122 NEXT;
3123 if (!IS_CHAR(CUR)) {
3124 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3125 } else {
3126 ret = xmlStrndup(q, CUR_PTR - q);
3127 NEXT;
3128 }
3129 } else if (CUR == '\'') {
3130 NEXT;
3131 q = CUR_PTR;
3132 while ((IS_CHAR(CUR)) && (CUR != '\''))
3133 NEXT;
3134 if (!IS_CHAR(CUR)) {
3135 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3136 } else {
3137 ret = xmlStrndup(q, CUR_PTR - q);
3138 NEXT;
3139 }
3140 } else {
3141 ERROR(XPATH_START_LITERAL_ERROR);
3142 }
3143 if (ret == NULL) return;
3144 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003145 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003146}
3147
3148/**
3149 * xmlXPathEvalVariableReference:
3150 * @ctxt: the XPath Parser context
3151 *
3152 * Parse a VariableReference, evaluate it and push it on the stack.
3153 *
3154 * The variable bindings consist of a mapping from variable names
3155 * to variable values. The value of a variable is an object, which
3156 * of any of the types that are possible for the value of an expression,
3157 * and may also be of additional types not specified here.
3158 *
3159 * Early evaluation is possible since:
3160 * The variable bindings [...] used to evaluate a subexpression are
3161 * always the same as those used to evaluate the containing expression.
3162 *
3163 * [36] VariableReference ::= '$' QName
3164 */
3165void
3166xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
3167 CHAR *name;
3168 CHAR *prefix;
3169 xmlXPathObjectPtr value;
3170
3171 if (CUR != '$') {
3172 ERROR(XPATH_VARIABLE_REF_ERROR);
3173 }
3174 name = xmlXPathParseQName(ctxt, &prefix);
3175 if (name == NULL) {
3176 ERROR(XPATH_VARIABLE_REF_ERROR);
3177 }
3178 value = xmlXPathVariablelookup(ctxt, prefix, name);
3179 if (value == NULL) {
3180 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3181 }
3182 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003183 if (prefix != NULL) xmlFree(prefix);
3184 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003185}
3186
3187
3188/**
3189 * xmlXPathFunctionLookup:
3190 * @ctxt: the XPath Parser context
3191 * @name: a name string
3192 *
3193 * Search for a function of the given name
3194 *
3195 * [35] FunctionName ::= QName - NodeType
3196 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003197 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003198 *
3199 * Returns the xmlXPathFunction if found, or NULL otherwise
3200 */
3201xmlXPathFunction
Daniel Veillardb96e6431999-08-29 21:02:19 +00003202xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const CHAR *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003203 switch (name[0]) {
3204 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003205 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003206 return(xmlXPathBooleanFunction);
3207 break;
3208 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003209 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003210 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003211 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003212 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003213 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003214 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003215 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003216 return(xmlXPathContainsFunction);
3217 break;
3218 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003219 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003220 return(xmlXPathIdFunction);
3221 break;
3222 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003223 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003224 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003225 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003226 return(xmlXPathFloorFunction);
3227 break;
3228 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003229 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003230 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003231 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003232 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003233 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003234 return(xmlXPathLocalPartFunction);
3235 break;
3236 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003237 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003238 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003239 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003240 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003241 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003242 return(xmlXPathNamespaceFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003243 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003244 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003245 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003246 return(xmlXPathNumberFunction);
3247 break;
3248 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003249 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003250 return(xmlXPathPositionFunction);
3251 break;
3252 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003253 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003254 return(xmlXPathRoundFunction);
3255 break;
3256 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003257 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003258 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003259 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003260 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003261 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003262 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003263 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003264 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003265 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003266 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003267 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003268 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003269 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003270 return(xmlXPathSumFunction);
3271 break;
3272 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003273 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003274 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003275 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003276 return(xmlXPathTranslateFunction);
3277 break;
3278 }
3279 return(NULL);
3280}
3281
3282/**
3283 * xmlXPathEvalLocationPathName:
3284 * @ctxt: the XPath Parser context
3285 * @name: a name string
3286 *
3287 * Various names in the beginning of a LocationPath expression
3288 * indicate whether that's an Axis, a node type,
3289 *
3290 * [6] AxisName ::= 'ancestor'
3291 * | 'ancestor-or-self'
3292 * | 'attribute'
3293 * | 'child'
3294 * | 'descendant'
3295 * | 'descendant-or-self'
3296 * | 'following'
3297 * | 'following-sibling'
3298 * | 'namespace'
3299 * | 'parent'
3300 * | 'preceding'
3301 * | 'preceding-sibling'
3302 * | 'self'
3303 * [38] NodeType ::= 'comment'
3304 * | 'text'
3305 * | 'processing-instruction'
3306 * | 'node'
3307 */
3308int
Daniel Veillardb96e6431999-08-29 21:02:19 +00003309xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const CHAR *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003310 switch (name[0]) {
3311 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003312 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3313 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3314 return(AXIS_ANCESTOR_OR_SELF);
3315 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003316 break;
3317 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003318 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3319 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003320 break;
3321 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003322 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3323 return(AXIS_DESCENDANT);
3324 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3325 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003326 break;
3327 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003328 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3329 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3330 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003331 break;
3332 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003333 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3334 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003335 break;
3336 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003337 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3338 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3339 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3340 return(AXIS_PRECEDING_SIBLING);
3341 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3342 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003343 break;
3344 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003345 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 break;
3347 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003348 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003349 break;
3350 }
3351 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3352 return(0);
3353}
3354
3355/**
3356 * xmlXPathEvalFunctionCall:
3357 * @ctxt: the XPath Parser context
3358 *
3359 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3360 * [17] Argument ::= Expr
3361 *
3362 * Parse and evaluate a function call, the evaluation of all arguments are
3363 * pushed on the stack
3364 */
3365void
3366xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
3367 CHAR *name;
3368 CHAR *prefix;
3369 xmlXPathFunction func;
3370 int nbargs = 0;
3371
3372 name = xmlXPathParseQName(ctxt, &prefix);
3373 if (name == NULL) {
3374 ERROR(XPATH_EXPR_ERROR);
3375 }
3376 func = xmlXPathIsFunction(ctxt, name);
3377 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003378 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003379 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3380 }
3381#ifdef DEBUG_EXPR
3382 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3383#endif
3384
3385 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003386 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003387 ERROR(XPATH_EXPR_ERROR);
3388 }
3389 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003390
3391 while (CUR != ')') {
3392 xmlXPathEvalExpr(ctxt);
3393 nbargs++;
3394 if (CUR == ')') break;
3395 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003396 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003397 ERROR(XPATH_EXPR_ERROR);
3398 }
3399 NEXT;
3400 }
3401 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003402 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003403 func(ctxt, nbargs);
3404}
3405
3406/**
3407 * xmlXPathEvalPrimaryExpr:
3408 * @ctxt: the XPath Parser context
3409 *
3410 * [15] PrimaryExpr ::= VariableReference
3411 * | '(' Expr ')'
3412 * | Literal
3413 * | Number
3414 * | FunctionCall
3415 *
3416 * Parse and evaluate a primary expression, then push the result on the stack
3417 */
3418void
3419xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
3420 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3421 else if (CUR == '(') {
3422 NEXT;
3423 xmlXPathEvalExpr(ctxt);
3424 if (CUR != ')') {
3425 ERROR(XPATH_EXPR_ERROR);
3426 }
3427 NEXT;
3428 } else if (IS_DIGIT(CUR)) {
3429 xmlXPathEvalNumber(ctxt);
3430 } else if ((CUR == '\'') || (CUR == '"')) {
3431 xmlXPathEvalLiteral(ctxt);
3432 } else {
3433 xmlXPathEvalFunctionCall(ctxt);
3434 }
3435}
3436
3437/**
3438 * xmlXPathEvalFilterExpr:
3439 * @ctxt: the XPath Parser context
3440 *
3441 * [20] FilterExpr ::= PrimaryExpr
3442 * | FilterExpr Predicate
3443 *
3444 * Parse and evaluate a filter expression, then push the result on the stack
3445 * Square brackets are used to filter expressions in the same way that
3446 * they are used in location paths. It is an error if the expression to
3447 * be filtered does not evaluate to a node-set. The context node list
3448 * used for evaluating the expression in square brackets is the node-set
3449 * to be filtered listed in document order.
3450 */
3451
3452void
3453xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3454 /****
3455 xmlNodeSetPtr oldset = NULL;
3456 xmlXPathObjectPtr arg;
3457 ****/
3458
3459 xmlXPathEvalPrimaryExpr(ctxt);
3460 CHECK_ERROR;
3461
3462 if (CUR != '[') return;
3463
3464 CHECK_TYPE(XPATH_NODESET);
3465
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003466 while (CUR == '[') {
3467 xmlXPathEvalPredicate(ctxt);
3468 }
3469
3470
3471}
3472
3473/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003474 * xmlXPathScanName:
3475 * @ctxt: the XPath Parser context
3476 *
3477 * Trickery: parse an XML name but without consuming the input flow
3478 * Needed for rollback cases.
3479 *
3480 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3481 * CombiningChar | Extender
3482 *
3483 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3484 *
3485 * [6] Names ::= Name (S Name)*
3486 *
3487 * Returns the Name parsed or NULL
3488 */
3489
3490CHAR *
3491xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
3492 CHAR buf[XML_MAX_NAMELEN];
3493 int len = 0;
3494
3495 if (!IS_LETTER(CUR) && (CUR != '_') &&
3496 (CUR != ':')) {
3497 return(NULL);
3498 }
3499
3500 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3501 (NXT(len) == '.') || (NXT(len) == '-') ||
3502 (NXT(len) == '_') || (NXT(len) == ':') ||
3503 (IS_COMBINING(NXT(len))) ||
3504 (IS_EXTENDER(NXT(len)))) {
3505 buf[len] = NXT(len);
3506 len++;
3507 if (len >= XML_MAX_NAMELEN) {
3508 fprintf(stderr,
3509 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3510 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3511 (NXT(len) == '.') || (NXT(len) == '-') ||
3512 (NXT(len) == '_') || (NXT(len) == ':') ||
3513 (IS_COMBINING(NXT(len))) ||
3514 (IS_EXTENDER(NXT(len))))
3515 len++;
3516 break;
3517 }
3518 }
3519 return(xmlStrndup(buf, len));
3520}
3521
3522/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003523 * xmlXPathEvalPathExpr:
3524 * @ctxt: the XPath Parser context
3525 *
3526 * [19] PathExpr ::= LocationPath
3527 * | FilterExpr
3528 * | FilterExpr '/' RelativeLocationPath
3529 * | FilterExpr '//' RelativeLocationPath
3530 *
3531 * Parse and evaluate a path expression, then push the result on the stack
3532 * The / operator and // operators combine an arbitrary expression
3533 * and a relative location path. It is an error if the expression
3534 * does not evaluate to a node-set.
3535 * The / operator does composition in the same way as when / is
3536 * used in a location path. As in location paths, // is short for
3537 * /descendant-or-self::node()/.
3538 */
3539
3540void
3541xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3542 xmlNodeSetPtr newset = NULL;
3543
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003544 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3545 (CUR == '\'') || (CUR == '"')) {
3546 xmlXPathEvalFilterExpr(ctxt);
3547 CHECK_ERROR;
3548 if ((CUR == '/') && (NXT(1) == '/')) {
3549 SKIP(2);
3550 if (ctxt->context->nodelist == NULL) {
3551 STRANGE
3552 xmlXPathRoot(ctxt);
3553 }
3554 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3555 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3556 if (ctxt->context->nodelist != NULL)
3557 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3558 ctxt->context->nodelist = newset;
3559 ctxt->context->node = NULL;
3560 xmlXPathEvalRelativeLocationPath(ctxt);
3561 } else if (CUR == '/') {
3562 xmlXPathEvalRelativeLocationPath(ctxt);
3563 }
3564 } else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003565 CHAR *name;
3566
3567 name = xmlXPathScanName(ctxt);
3568 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3569 xmlXPathEvalLocationPath(ctxt);
3570 else
3571 xmlXPathEvalFilterExpr(ctxt);
3572 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003573 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003574 }
3575}
3576
3577/**
3578 * xmlXPathEvalUnionExpr:
3579 * @ctxt: the XPath Parser context
3580 *
3581 * [18] UnionExpr ::= PathExpr
3582 * | UnionExpr '|' PathExpr
3583 *
3584 * Parse and evaluate an union expression, then push the result on the stack
3585 */
3586
3587void
3588xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3589 xmlXPathEvalPathExpr(ctxt);
3590 CHECK_ERROR;
3591 if (CUR == '|') {
3592 xmlNodeSetPtr old = ctxt->context->nodelist;
3593
3594 xmlXPathEvalPathExpr(ctxt);
3595
3596 if (ctxt->context->nodelist == NULL)
3597 ctxt->context->nodelist = old;
3598 else {
3599 ctxt->context->nodelist =
3600 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3601 xmlXPathFreeNodeSet(old);
3602 }
3603 }
3604}
3605
3606/**
3607 * xmlXPathEvalUnaryExpr:
3608 * @ctxt: the XPath Parser context
3609 *
3610 * [27] UnaryExpr ::= UnionExpr
3611 * | '-' UnaryExpr
3612 *
3613 * Parse and evaluate an unary expression, then push the result on the stack
3614 */
3615
3616void
3617xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3618 int minus = 0;
3619
3620 if (CUR == '-') {
3621 minus = 1;
3622 NEXT;
3623 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003624 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003625 CHECK_ERROR;
3626 if (minus) {
3627 xmlXPathValueFlipSign(ctxt);
3628 }
3629}
3630
3631/**
3632 * xmlXPathEvalMultiplicativeExpr:
3633 * @ctxt: the XPath Parser context
3634 *
3635 * [26] MultiplicativeExpr ::= UnaryExpr
3636 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3637 * | MultiplicativeExpr 'div' UnaryExpr
3638 * | MultiplicativeExpr 'mod' UnaryExpr
3639 * [34] MultiplyOperator ::= '*'
3640 *
3641 * Parse and evaluate an Additive expression, then push the result on the stack
3642 */
3643
3644void
3645xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3646 xmlXPathEvalUnaryExpr(ctxt);
3647 CHECK_ERROR;
3648 while ((CUR == '*') ||
3649 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3650 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3651 int op = -1;
3652
3653 if (CUR == '*') {
3654 op = 0;
3655 NEXT;
3656 } else if (CUR == 'd') {
3657 op = 1;
3658 SKIP(3);
3659 } else if (CUR == 'm') {
3660 op = 2;
3661 SKIP(3);
3662 }
3663 xmlXPathEvalUnaryExpr(ctxt);
3664 CHECK_ERROR;
3665 switch (op) {
3666 case 0:
3667 xmlXPathMultValues(ctxt);
3668 break;
3669 case 1:
3670 xmlXPathDivValues(ctxt);
3671 break;
3672 case 2:
3673 xmlXPathModValues(ctxt);
3674 break;
3675 }
3676 }
3677}
3678
3679/**
3680 * xmlXPathEvalAdditiveExpr:
3681 * @ctxt: the XPath Parser context
3682 *
3683 * [25] AdditiveExpr ::= MultiplicativeExpr
3684 * | AdditiveExpr '+' MultiplicativeExpr
3685 * | AdditiveExpr '-' MultiplicativeExpr
3686 *
3687 * Parse and evaluate an Additive expression, then push the result on the stack
3688 */
3689
3690void
3691xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3692 xmlXPathEvalMultiplicativeExpr(ctxt);
3693 CHECK_ERROR;
3694 while ((CUR == '+') || (CUR == '-')) {
3695 int plus;
3696
3697 if (CUR == '+') plus = 1;
3698 else plus = 0;
3699 NEXT;
3700 xmlXPathEvalMultiplicativeExpr(ctxt);
3701 CHECK_ERROR;
3702 if (plus) xmlXPathAddValues(ctxt);
3703 else xmlXPathSubValues(ctxt);
3704 }
3705}
3706
3707/**
3708 * xmlXPathEvalRelationalExpr:
3709 * @ctxt: the XPath Parser context
3710 *
3711 * [24] RelationalExpr ::= AdditiveExpr
3712 * | RelationalExpr '<' AdditiveExpr
3713 * | RelationalExpr '>' AdditiveExpr
3714 * | RelationalExpr '<=' AdditiveExpr
3715 * | RelationalExpr '>=' AdditiveExpr
3716 *
3717 * A <= B > C is allowed ? Answer from James, yes with
3718 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3719 * which is basically what got implemented.
3720 *
3721 * Parse and evaluate a Relational expression, then push the result
3722 * on the stack
3723 */
3724
3725void
3726xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3727 xmlXPathEvalAdditiveExpr(ctxt);
3728 CHECK_ERROR;
3729 while ((CUR == '<') ||
3730 (CUR == '>') ||
3731 ((CUR == '<') && (NXT(1) == '=')) ||
3732 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003733 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003734
3735 if (CUR == '<') inf = 1;
3736 else inf = 0;
3737 if (NXT(1) == '=') strict = 0;
3738 else strict = 1;
3739 NEXT;
3740 if (!strict) NEXT;
3741 xmlXPathEvalAdditiveExpr(ctxt);
3742 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003743 ret = xmlXPathCompareValues(ctxt, inf, strict);
3744 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003745 }
3746}
3747
3748/**
3749 * xmlXPathEvalEqualityExpr:
3750 * @ctxt: the XPath Parser context
3751 *
3752 * [23] EqualityExpr ::= RelationalExpr
3753 * | EqualityExpr '=' RelationalExpr
3754 * | EqualityExpr '!=' RelationalExpr
3755 *
3756 * A != B != C is allowed ? Answer from James, yes with
3757 * (RelationalExpr = RelationalExpr) = RelationalExpr
3758 * (RelationalExpr != RelationalExpr) != RelationalExpr
3759 * which is basically what got implemented.
3760 *
3761 * Parse and evaluate an Equality expression, then push the result on the stack
3762 *
3763 */
3764void
3765xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3766 xmlXPathEvalRelationalExpr(ctxt);
3767 CHECK_ERROR;
3768 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003769 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003770 int eq, equal;
3771
3772 if (CUR == '=') eq = 1;
3773 else eq = 0;
3774 NEXT;
3775 if (!eq) NEXT;
3776 xmlXPathEvalRelationalExpr(ctxt);
3777 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003778 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003779 if (eq) res = xmlXPathNewBoolean(equal);
3780 else res = xmlXPathNewBoolean(!equal);
3781 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003782 }
3783}
3784
3785/**
3786 * xmlXPathEvalAndExpr:
3787 * @ctxt: the XPath Parser context
3788 *
3789 * [22] AndExpr ::= EqualityExpr
3790 * | AndExpr 'and' EqualityExpr
3791 *
3792 * Parse and evaluate an AND expression, then push the result on the stack
3793 *
3794 */
3795void
3796xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3797 xmlXPathEvalEqualityExpr(ctxt);
3798 CHECK_ERROR;
3799 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3800 xmlXPathObjectPtr arg1, arg2;
3801
3802 SKIP(3);
3803 xmlXPathEvalEqualityExpr(ctxt);
3804 CHECK_ERROR;
3805 arg2 = valuePop(ctxt);
3806 arg1 = valuePop(ctxt);
3807 arg1->boolval &= arg2->boolval;
3808 valuePush(ctxt, arg1);
3809 xmlXPathFreeObject(arg2);
3810 }
3811}
3812
3813/**
3814 * xmlXPathEvalExpr:
3815 * @ctxt: the XPath Parser context
3816 *
3817 * [14] Expr ::= OrExpr
3818 * [21] OrExpr ::= AndExpr
3819 * | OrExpr 'or' AndExpr
3820 *
3821 * Parse and evaluate an expression, then push the result on the stack
3822 *
3823 */
3824void
3825xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3826 xmlXPathEvalAndExpr(ctxt);
3827 CHECK_ERROR;
3828 while ((CUR == 'o') && (NXT(1) == 'r')) {
3829 xmlXPathObjectPtr arg1, arg2;
3830
3831 SKIP(2);
3832 xmlXPathEvalAndExpr(ctxt);
3833 CHECK_ERROR;
3834 arg2 = valuePop(ctxt);
3835 arg1 = valuePop(ctxt);
3836 arg1->boolval |= arg2->boolval;
3837 valuePush(ctxt, arg1);
3838 xmlXPathFreeObject(arg2);
3839 }
3840}
3841
3842/**
3843 * xmlXPathEvaluatePredicateResult:
3844 * @ctxt: the XPath Parser context
3845 * @res: the Predicate Expression evaluation result
3846 * @index: index of the current node in the current list
3847 *
3848 * Evaluate a predicate result for the current node.
3849 * A PredicateExpr is evaluated by evaluating the Expr and converting
3850 * the result to a boolean. If the result is a number, the result will
3851 * be converted to true if the number is equal to the position of the
3852 * context node in the context node list (as returned by the position
3853 * function) and will be converted to false otherwise; if the result
3854 * is not a number, then the result will be converted as if by a call
3855 * to the boolean function.
3856 */
3857int
3858xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3859 xmlXPathObjectPtr res, int index) {
3860 if (res == NULL) return(0);
3861 switch (res->type) {
3862 case XPATH_BOOLEAN:
3863 return(res->boolval);
3864 case XPATH_NUMBER:
3865 return(res->floatval == index);
3866 case XPATH_NODESET:
3867 return(res->nodesetval->nodeNr != 0);
3868 case XPATH_STRING:
3869 return((res->stringval != NULL) &&
3870 (xmlStrlen(res->stringval) != 0));
3871 default:
3872 STRANGE
3873 }
3874 return(0);
3875}
3876
3877/**
3878 * xmlXPathEvalPredicate:
3879 * @ctxt: the XPath Parser context
3880 *
3881 * [8] Predicate ::= '[' PredicateExpr ']'
3882 * [9] PredicateExpr ::= Expr
3883 *
3884 * Parse and evaluate a predicate for all the elements of the
3885 * current node list. Then refine the list by removing all
3886 * nodes where the predicate is false.
3887 */
3888void
3889xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
3890 const CHAR *cur;
3891 xmlXPathObjectPtr res;
3892 xmlNodeSetPtr newset = NULL;
3893 int i;
3894
3895 if (CUR != '[') {
3896 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3897 }
3898 NEXT;
3899 if ((ctxt->context->nodelist == NULL) ||
3900 (ctxt->context->nodelist->nodeNr == 0)) {
3901 ctxt->context->node = NULL;
3902 xmlXPathEvalExpr(ctxt);
3903 CHECK_ERROR;
3904 res = valuePop(ctxt);
3905 if (res != NULL)
3906 xmlXPathFreeObject(res);
3907 } else {
3908 cur = ctxt->cur;
3909 newset = xmlXPathNodeSetCreate(NULL);
3910 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3911 ctxt->cur = cur;
3912 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3913 xmlXPathEvalExpr(ctxt);
3914 CHECK_ERROR;
3915 res = valuePop(ctxt);
3916 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3917 xmlXPathNodeSetAdd(newset,
3918 ctxt->context->nodelist->nodeTab[i]);
3919 if (res != NULL)
3920 xmlXPathFreeObject(res);
3921 }
3922 if (ctxt->context->nodelist != NULL)
3923 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3924 ctxt->context->nodelist = newset;
3925 ctxt->context->node = NULL;
3926 }
3927 if (CUR != ']') {
3928 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3929 }
3930 NEXT;
3931#ifdef DEBUG_STEP
3932 fprintf(xmlXPathDebug, "After predicate : ");
3933 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3934#endif
3935}
3936
3937/**
3938 * xmlXPathEvalBasis:
3939 * @ctxt: the XPath Parser context
3940 *
3941 * [5] Basis ::= AxisName '::' NodeTest
3942 * | AbbreviatedBasis
3943 * [13] AbbreviatedBasis ::= NodeTest
3944 * | '@' NodeTest
3945 * [7] NodeTest ::= WildcardName
3946 * | NodeType '(' ')'
3947 * | 'processing-instruction' '(' Literal ')'
3948 * [37] WildcardName ::= '*'
3949 * | NCName ':' '*'
3950 * | QName
3951 *
3952 * Evaluate one step in a Location Path
3953 */
3954void
3955xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
3956 CHAR *name = NULL;
3957 CHAR *prefix = NULL;
3958 int type = 0;
3959 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
3960 int nodetest = NODE_TEST_NONE;
3961 int nodetype = 0;
3962 xmlNodeSetPtr newset = NULL;
3963
3964 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003965 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003966 axis = AXIS_ATTRIBUTE;
3967 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003968 } else if (CUR == '*') {
3969 NEXT;
3970 nodetest = NODE_TEST_ALL;
3971 } else {
3972 name = xmlXPathParseNCName(ctxt);
3973 if (name == NULL) {
3974 ERROR(XPATH_EXPR_ERROR);
3975 }
3976 type = xmlXPathGetNameType(ctxt, name);
3977 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003978 case IS_FUNCTION: {
3979 xmlXPathFunction func;
3980 int nbargs = 0;
3981 xmlXPathObjectPtr top;
3982
3983 top = ctxt->value;
3984 func = xmlXPathIsFunction(ctxt, name);
3985 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003986 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003987 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3988 }
3989#ifdef DEBUG_EXPR
3990 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3991#endif
3992
3993 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003994 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003995 ERROR(XPATH_EXPR_ERROR);
3996 }
3997 NEXT;
3998
3999 while (CUR != ')') {
4000 xmlXPathEvalExpr(ctxt);
4001 nbargs++;
4002 if (CUR == ')') break;
4003 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004004 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004005 ERROR(XPATH_EXPR_ERROR);
4006 }
4007 NEXT;
4008 }
4009 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004010 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004011 func(ctxt, nbargs);
4012 if ((ctxt->value != top) &&
4013 (ctxt->value != NULL) &&
4014 (ctxt->value->type == XPATH_NODESET)) {
4015 xmlXPathObjectPtr cur;
4016
4017 cur = valuePop(ctxt);
4018 ctxt->context->nodelist = cur->nodesetval;
4019 ctxt->context->node = NULL;
4020 cur->nodesetval = NULL;
4021 xmlXPathFreeObject(cur);
4022 }
4023 return;
4024 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004025 /*
4026 * Simple case: no axis seach all given node types.
4027 */
4028 case NODE_TYPE_COMMENT:
4029 if ((CUR != '(') || (NXT(1) != ')')) break;
4030 SKIP(2);
4031 nodetest = NODE_TEST_TYPE;
4032 nodetype = XML_COMMENT_NODE;
4033 goto search_nodes;
4034 case NODE_TYPE_TEXT:
4035 if ((CUR != '(') || (NXT(1) != ')')) break;
4036 SKIP(2);
4037 nodetest = NODE_TEST_TYPE;
4038 nodetype = XML_TEXT_NODE;
4039 goto search_nodes;
4040 case NODE_TYPE_NODE:
4041 if ((CUR != '(') || (NXT(1) != ')')) {
4042 nodetest = NODE_TEST_NAME;
4043 break;
4044 }
4045 SKIP(2);
4046 nodetest = NODE_TEST_TYPE;
4047 nodetype = XML_ELEMENT_NODE;
4048 goto search_nodes;
4049 case NODE_TYPE_PI:
4050 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004051 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004052 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004053 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004054 xmlXPathObjectPtr cur;
4055
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004056 /*
4057 * Specific case: search a PI by name.
4058 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004059 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004060 nodetest = NODE_TEST_PI;
4061 xmlXPathEvalLiteral(ctxt);
4062 CHECK_ERROR;
4063 if (CUR != ')')
4064 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004065 NEXT;
4066 xmlXPathStringFunction(ctxt, 1);
4067 CHECK_ERROR;
4068 cur = valuePop(ctxt);
4069 name = xmlStrdup(cur->stringval);
4070 xmlXPathFreeObject(cur);
4071 } else
4072 SKIP(2);
4073 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004074 goto search_nodes;
4075
4076 /*
4077 * Handling of the compund form: got the axis.
4078 */
4079 case AXIS_ANCESTOR:
4080 case AXIS_ANCESTOR_OR_SELF:
4081 case AXIS_ATTRIBUTE:
4082 case AXIS_CHILD:
4083 case AXIS_DESCENDANT:
4084 case AXIS_DESCENDANT_OR_SELF:
4085 case AXIS_FOLLOWING:
4086 case AXIS_FOLLOWING_SIBLING:
4087 case AXIS_NAMESPACE:
4088 case AXIS_PARENT:
4089 case AXIS_PRECEDING:
4090 case AXIS_PRECEDING_SIBLING:
4091 case AXIS_SELF:
4092 if ((CUR != ':') || (NXT(1) != ':')) {
4093 nodetest = NODE_TEST_NAME;
4094 break;
4095 }
4096 SKIP(2);
4097 axis = type;
4098 break;
4099
4100 /*
4101 * Default: abbreviated syntax the axis is AXIS_CHILD
4102 */
4103 default:
4104 nodetest = NODE_TEST_NAME;
4105 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004106parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004107 if (nodetest == NODE_TEST_NONE) {
4108 if (CUR == '*') {
4109 NEXT;
4110 nodetest = NODE_TEST_ALL;
4111 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004112 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004113 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004114 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004115 if (name == NULL) {
4116 ERROR(XPATH_EXPR_ERROR);
4117 }
4118 type = xmlXPathGetNameType(ctxt, name);
4119 switch (type) {
4120 /*
4121 * Simple case: no axis seach all given node types.
4122 */
4123 case NODE_TYPE_COMMENT:
4124 if ((CUR != '(') || (NXT(1) != ')')) break;
4125 SKIP(2);
4126 nodetest = NODE_TEST_TYPE;
4127 nodetype = XML_COMMENT_NODE;
4128 goto search_nodes;
4129 case NODE_TYPE_TEXT:
4130 if ((CUR != '(') || (NXT(1) != ')')) break;
4131 SKIP(2);
4132 nodetest = NODE_TEST_TYPE;
4133 nodetype = XML_TEXT_NODE;
4134 goto search_nodes;
4135 case NODE_TYPE_NODE:
4136 if ((CUR != '(') || (NXT(1) != ')')) {
4137 nodetest = NODE_TEST_NAME;
4138 break;
4139 }
4140 SKIP(2);
4141 nodetest = NODE_TEST_TYPE;
4142 nodetype = XML_ELEMENT_NODE;
4143 goto search_nodes;
4144 case NODE_TYPE_PI:
4145 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004146 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004147 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004148 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004149 xmlXPathObjectPtr cur;
4150
Daniel Veillardb05deb71999-08-10 19:04:08 +00004151 /*
4152 * Specific case: search a PI by name.
4153 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004154 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004155 nodetest = NODE_TEST_PI;
4156 xmlXPathEvalLiteral(ctxt);
4157 CHECK_ERROR;
4158 if (CUR != ')')
4159 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004160 NEXT;
4161 xmlXPathStringFunction(ctxt, 1);
4162 CHECK_ERROR;
4163 cur = valuePop(ctxt);
4164 name = xmlStrdup(cur->stringval);
4165 xmlXPathFreeObject(cur);
4166 } else
4167 SKIP(2);
4168 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004169 goto search_nodes;
4170 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004171 nodetest = NODE_TEST_NAME;
4172 }
4173 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4174 NEXT;
4175 prefix = name;
4176 if (CUR == '*') {
4177 NEXT;
4178 nodetest = NODE_TEST_ALL;
4179 } else
4180 name = xmlXPathParseNCName(ctxt);
4181 } else if (name == NULL)
4182 ERROR(XPATH_EXPR_ERROR);
4183 }
4184
4185search_nodes:
4186
4187#ifdef DEBUG_STEP
4188 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4189#endif
4190 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4191 prefix, name);
4192 if (ctxt->context->nodelist != NULL)
4193 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4194 ctxt->context->nodelist = newset;
4195 ctxt->context->node = NULL;
4196#ifdef DEBUG_STEP
4197 fprintf(xmlXPathDebug, "Basis : ");
4198 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4199#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004200 if (name != NULL) xmlFree(name);
4201 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004202}
4203
4204/**
4205 * xmlXPathEvalStep:
4206 * @ctxt: the XPath Parser context
4207 *
4208 * [4] Step ::= Basis Predicate*
4209 * | AbbreviatedStep
4210 * [12] AbbreviatedStep ::= '.'
4211 * | '..'
4212 *
4213 * Evaluate one step in a Location Path
4214 * A location step of . is short for self::node(). This is
4215 * particularly useful in conjunction with //. For example, the
4216 * location path .//para is short for
4217 * self::node()/descendant-or-self::node()/child::para
4218 * and so will select all para descendant elements of the context
4219 * node.
4220 * Similarly, a location step of .. is short for parent::node().
4221 * For example, ../title is short for parent::node()/child::title
4222 * and so will select the title children of the parent of the context
4223 * node.
4224 */
4225void
4226xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4227 xmlNodeSetPtr newset = NULL;
4228
4229 if ((CUR == '.') && (NXT(1) == '.')) {
4230 SKIP(2);
4231 if (ctxt->context->nodelist == NULL) {
4232 STRANGE
4233 xmlXPathRoot(ctxt);
4234 }
4235 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4236 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4237 if (ctxt->context->nodelist != NULL)
4238 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4239 ctxt->context->nodelist = newset;
4240 ctxt->context->node = NULL;
4241 } else if (CUR == '.') {
4242 NEXT;
4243 } else {
4244 xmlXPathEvalBasis(ctxt);
4245 while (CUR == '[') {
4246 xmlXPathEvalPredicate(ctxt);
4247 }
4248 }
4249#ifdef DEBUG_STEP
4250 fprintf(xmlXPathDebug, "Step : ");
4251 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4252#endif
4253}
4254
4255/**
4256 * xmlXPathEvalRelativeLocationPath:
4257 * @ctxt: the XPath Parser context
4258 *
4259 * [3] RelativeLocationPath ::= Step
4260 * | RelativeLocationPath '/' Step
4261 * | AbbreviatedRelativeLocationPath
4262 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4263 *
4264 */
4265void
4266xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4267 xmlNodeSetPtr newset = NULL;
4268
4269 xmlXPathEvalStep(ctxt);
4270 while (CUR == '/') {
4271 if ((CUR == '/') && (NXT(1) == '/')) {
4272 SKIP(2);
4273 if (ctxt->context->nodelist == NULL) {
4274 STRANGE
4275 xmlXPathRoot(ctxt);
4276 }
4277 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4278 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4279 if (ctxt->context->nodelist != NULL)
4280 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4281 ctxt->context->nodelist = newset;
4282 ctxt->context->node = NULL;
4283 xmlXPathEvalStep(ctxt);
4284 } else if (CUR == '/') {
4285 NEXT;
4286 xmlXPathEvalStep(ctxt);
4287 }
4288 }
4289}
4290
4291/**
4292 * xmlXPathEvalLocationPath:
4293 * @ctxt: the XPath Parser context
4294 *
4295 * [1] LocationPath ::= RelativeLocationPath
4296 * | AbsoluteLocationPath
4297 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4298 * | AbbreviatedAbsoluteLocationPath
4299 * [10] AbbreviatedAbsoluteLocationPath ::=
4300 * '//' RelativeLocationPath
4301 *
4302 * // is short for /descendant-or-self::node()/. For example,
4303 * //para is short for /descendant-or-self::node()/child::para and
4304 * so will select any para element in the document (even a para element
4305 * that is a document element will be selected by //para since the
4306 * document element node is a child of the root node); div//para is
4307 * short for div/descendant-or-self::node()/child::para and so will
4308 * select all para descendants of div children.
4309 */
4310void
4311xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4312 xmlNodeSetPtr newset = NULL;
4313
4314 while (CUR == '/') {
4315 if ((CUR == '/') && (NXT(1) == '/')) {
4316 SKIP(2);
4317 if (ctxt->context->nodelist == NULL)
4318 xmlXPathRoot(ctxt);
4319 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4320 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4321 if (ctxt->context->nodelist != NULL)
4322 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4323 ctxt->context->nodelist = newset;
4324 ctxt->context->node = NULL;
4325 xmlXPathEvalRelativeLocationPath(ctxt);
4326 } else if (CUR == '/') {
4327 NEXT;
4328 xmlXPathRoot(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004329 if (CUR != 0)
4330 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004331 } else {
4332 xmlXPathEvalRelativeLocationPath(ctxt);
4333 }
4334 }
4335}
4336
4337/*
4338 * TODO * extra spaces *
4339 * more tokenization rules ... Not used currently, especially allowing
4340 * spaces before and after ExprToken !!!!!!!!!!!!!
4341 *
4342 * [32] Operator ::= OperatorName
4343 * | MultiplyOperator
4344 * | '/' | '//' | '|' | '+' | '-' | '=' | '!='
4345 * | '<'| '<=' | '>' | '>='
4346 * [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
4347 * [39] ExprWhitespace ::= S
4348 *
4349 * BUG: ExprToken is never referenced.
4350 *
4351 * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
4352 * | WildcardName
4353 * | NodeType
4354 * | Operator
4355 * | FunctionName
4356 * | AxisName
4357 * | Literal
4358 * | Number
4359 * | VariableReference
4360 */
4361
4362/**
4363 * xmlXPathEval:
4364 * @str: the XPath expression
4365 * @ctxt: the XPath context
4366 *
4367 * Evaluate the XPath Location Path in the given context.
4368 *
4369 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4370 * the caller has to free the object.
4371 */
4372xmlXPathObjectPtr
4373xmlXPathEval(const CHAR *str, xmlXPathContextPtr ctxt) {
4374 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004375 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004376
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004377 xmlXPathInit();
4378
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004379 CHECK_CONTEXT
4380
4381 if (xmlXPathDebug == NULL)
4382 xmlXPathDebug = stderr;
4383 pctxt = xmlXPathNewParserContext(str, ctxt);
4384 xmlXPathEvalLocationPath(pctxt);
4385
Daniel Veillardb96e6431999-08-29 21:02:19 +00004386 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004387 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004388 tmp = valuePop(pctxt);
4389 if (tmp != NULL);
4390 xmlXPathFreeObject(tmp);
4391 } while (tmp != NULL);
4392 if (res == NULL)
4393 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004394 xmlXPathFreeParserContext(pctxt);
4395 return(res);
4396}
4397
4398/**
4399 * xmlXPathEvalExpression:
4400 * @str: the XPath expression
4401 * @ctxt: the XPath context
4402 *
4403 * Evaluate the XPath expression in the given context.
4404 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004405 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004406 * the caller has to free the object.
4407 */
4408xmlXPathObjectPtr
4409xmlXPathEvalExpression(const CHAR *str, xmlXPathContextPtr ctxt) {
4410 xmlXPathParserContextPtr pctxt;
4411 xmlXPathObjectPtr res, tmp;
4412
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004413 xmlXPathInit();
4414
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004415 CHECK_CONTEXT
4416
4417 if (xmlXPathDebug == NULL)
4418 xmlXPathDebug = stderr;
4419 pctxt = xmlXPathNewParserContext(str, ctxt);
4420 xmlXPathEvalExpr(pctxt);
4421
4422 res = valuePop(pctxt);
4423 do {
4424 tmp = valuePop(pctxt);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004425 if (tmp != NULL);
4426 xmlXPathFreeObject(tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004427 } while (tmp != NULL);
4428 xmlXPathFreeParserContext(pctxt);
4429 return(res);
4430}
4431