blob: bb94ab85114992d996a4098dc14a43c604b4a4df [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
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#else
19#include "config.h"
20#endif
21
22#include <stdio.h>
23#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000028#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000029#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000030#endif
31#ifdef HAVE_MATH_H
32#include <float.h>
33#endif
34#ifdef HAVE_IEEEFP_H
35#include <ieeefp.h>
36#endif
37#ifdef HAVE_NAN_H
38#include <nan.h>
39#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000040#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000041#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000042#endif
43
Daniel Veillard6454aec1999-09-02 22:04:43 +000044#include "xmlmemory.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000045#include "tree.h"
Daniel Veillardb96e6431999-08-29 21:02:19 +000046#include "valid.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000047#include "xpath.h"
48#include "parserInternals.h"
49
Daniel Veillarddbfd6411999-12-28 16:35:14 +000050/* #define DEBUG */
51/* #define DEBUG_STEP */
52/* #define DEBUG_EXPR */
53
Daniel Veillard1566d3a1999-07-15 14:24:29 +000054/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000055 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000056 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000057 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000058double xmlXPathNAN = 0;
59double xmlXPathPINF = 1;
60double xmlXPathMINF = -1;
61
Daniel Veillardb05deb71999-08-10 19:04:08 +000062#ifndef isinf
63#ifndef HAVE_ISINF
64
65#if HAVE_FPCLASS
66
67int isinf(double d) {
68 fpclass_t type = fpclass(d);
69 switch (type) {
70 case FP_NINF:
71 return(-1);
72 case FP_PINF:
73 return(1);
74 default:
75 return(0);
76 }
77 return(0);
78}
79
80#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
81
82#if HAVE_FP_CLASS_H
83#include <fp_class.h>
84#endif
85
86int isinf(double d) {
87#if HAVE_FP_CLASS
88 int fpclass = fp_class(d);
89#else
90 int fpclass = fp_class_d(d);
91#endif
92 if (fpclass == FP_POS_INF)
93 return(1);
94 if (fpclass == FP_NEG_INF)
95 return(-1);
96 return(0);
97}
98
99#elif defined(HAVE_CLASS)
100
101int isinf(double d) {
102 int fpclass = class(d);
103 if (fpclass == FP_PLUS_INF)
104 return(1);
105 if (fpclass == FP_MINUS_INF)
106 return(-1);
107 return(0);
108}
109#elif defined(finite) || defined(HAVE_FINITE)
110int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000111#elif defined(HUGE_VAL)
112static int isinf(double x)
113{
114 if (x == HUGE_VAL)
115 return(1);
116 if (x == -HUGE_VAL)
117 return(-1);
118 return(0);
119}
120#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000121
122#endif /* ! HAVE_ISINF */
123#endif /* ! defined(isinf) */
124
125#ifndef isnan
126#ifndef HAVE_ISNAN
127
128#ifdef HAVE_ISNAND
129#define isnan(f) isnand(f)
130#endif /* HAVE_iSNAND */
131
132#endif /* ! HAVE_iSNAN */
133#endif /* ! defined(isnan) */
134
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000135/**
136 * xmlXPathInit:
137 *
138 * Initialize the XPath environment
139 */
140void
141xmlXPathInit(void) {
142 static int initialized = 0;
143
144 if (initialized) return;
145
146 xmlXPathNAN = 0;
147 xmlXPathNAN /= 0;
148
149 xmlXPathPINF = 1;
150 xmlXPathPINF /= 0;
151
152 xmlXPathMINF = -1;
153 xmlXPathMINF /= 0;
154
155 initialized = 1;
156}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000157
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000158FILE *xmlXPathDebug = NULL;
159
160#define TODO \
161 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
162 __FILE__, __LINE__);
163
164#define STRANGE \
165 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
166 __FILE__, __LINE__);
167
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000168double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000169void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000170
171/************************************************************************
172 * *
173 * Parser stacks related functions and macros *
174 * *
175 ************************************************************************/
176
177/*
178 * Generic function for accessing stacks in the Parser Context
179 */
180
181#define PUSH_AND_POP(type, name) \
182extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
183 if (ctxt->name##Nr >= ctxt->name##Max) { \
184 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000185 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000186 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
187 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000188 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000189 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000190 } \
191 } \
192 ctxt->name##Tab[ctxt->name##Nr] = value; \
193 ctxt->name = value; \
194 return(ctxt->name##Nr++); \
195} \
196extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
197 type ret; \
198 if (ctxt->name##Nr <= 0) return(0); \
199 ctxt->name##Nr--; \
200 if (ctxt->name##Nr > 0) \
201 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
202 else \
203 ctxt->name = NULL; \
204 ret = ctxt->name##Tab[ctxt->name##Nr]; \
205 ctxt->name##Tab[ctxt->name##Nr] = 0; \
206 return(ret); \
207} \
208
209PUSH_AND_POP(xmlXPathObjectPtr, value)
210
211/*
212 * Macros for accessing the content. Those should be used only by the parser,
213 * and not exported.
214 *
215 * Dirty macros, i.e. one need to make assumption on the context to use them
216 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000217 * CUR_PTR return the current pointer to the xmlChar to be parsed.
218 * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000219 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
220 * in UNICODE mode. This should be used internally by the parser
221 * only to compare to ASCII values otherwise it would break when
222 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000223 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000224 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000225 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000226 * strings within the parser.
227 * CURRENT Returns the current char value, with the full decoding of
228 * UTF-8 if we are using this mode. It returns an int.
229 * NEXT Skip to the next character, this does the proper decoding
230 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000231 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000232 */
233
234#define CUR (*ctxt->cur)
235#define SKIP(val) ctxt->cur += (val)
236#define NXT(val) ctxt->cur[(val)]
237#define CUR_PTR ctxt->cur
238
239#define SKIP_BLANKS \
240 while (IS_BLANK(*(ctxt->cur))) NEXT
241
242#ifndef USE_UTF_8
243#define CURRENT (*ctxt->cur)
244#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
245#else
246#endif
247
248/************************************************************************
249 * *
250 * Error handling routines *
251 * *
252 ************************************************************************/
253
254#define XPATH_EXPRESSION_OK 0
255#define XPATH_NUMBER_ERROR 1
256#define XPATH_UNFINISHED_LITERAL_ERROR 2
257#define XPATH_START_LITERAL_ERROR 3
258#define XPATH_VARIABLE_REF_ERROR 4
259#define XPATH_UNDEF_VARIABLE_ERROR 5
260#define XPATH_INVALID_PREDICATE_ERROR 6
261#define XPATH_EXPR_ERROR 7
262#define XPATH_UNCLOSED_ERROR 8
263#define XPATH_UNKNOWN_FUNC_ERROR 9
264#define XPATH_INVALID_OPERAND 10
265#define XPATH_INVALID_TYPE 11
266#define XPATH_INVALID_ARITY 12
267
268const char *xmlXPathErrorMessages[] = {
269 "Ok",
270 "Number encoding",
271 "Unfinished litteral",
272 "Start of litteral",
273 "Expected $ for variable reference",
274 "Undefined variable",
275 "Invalid predicate",
276 "Invalid expression",
277 "Missing closing curly brace",
278 "Unregistered function",
279 "Invalid operand",
280 "Invalid type",
281 "Invalid number of arguments",
282};
283
284/**
285 * xmlXPathError:
286 * @ctxt: the XPath Parser context
287 * @file: the file name
288 * @line: the line number
289 * @no: the error number
290 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000291 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000292 *
293 * Returns the newly created object.
294 */
295void
296xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
297 int line, int no) {
298 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000299 const xmlChar *cur;
300 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000301
302 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
303 xmlXPathErrorMessages[no]);
304
305 cur = ctxt->cur;
306 base = ctxt->base;
307 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
308 cur--;
309 }
310 n = 0;
311 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
312 cur--;
313 if ((*cur == '\n') || (*cur == '\r')) cur++;
314 base = cur;
315 n = 0;
316 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
317 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
318 n++;
319 }
320 fprintf(xmlXPathDebug, "\n");
321 cur = ctxt->cur;
322 while ((*cur == '\n') || (*cur == '\r'))
323 cur--;
324 n = 0;
325 while ((cur != base) && (n++ < 80)) {
326 fprintf(xmlXPathDebug, " ");
327 base++;
328 }
329 fprintf(xmlXPathDebug,"^\n");
330}
331
332#define CHECK_ERROR \
333 if (ctxt->error != XPATH_EXPRESSION_OK) return
334
335#define ERROR(X) \
336 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
337 ctxt->error = (X); return; }
338
Daniel Veillard991e63d1999-08-15 23:32:28 +0000339#define ERROR0(X) \
340 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
341 ctxt->error = (X); return(0); }
342
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000343#define CHECK_TYPE(typeval) \
344 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
345 ERROR(XPATH_INVALID_TYPE) \
346
347
348/************************************************************************
349 * *
350 * Routines to handle NodeSets *
351 * *
352 ************************************************************************/
353
354#define XML_NODESET_DEFAULT 10
355/**
356 * xmlXPathNodeSetCreate:
357 * @val: an initial xmlNodePtr, or NULL
358 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000359 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000360 *
361 * Returns the newly created object.
362 */
363xmlNodeSetPtr
364xmlXPathNodeSetCreate(xmlNodePtr val) {
365 xmlNodeSetPtr ret;
366
Daniel Veillard6454aec1999-09-02 22:04:43 +0000367 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000368 if (ret == NULL) {
369 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
370 return(NULL);
371 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000372 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000373 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000374 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000375 sizeof(xmlNodePtr));
376 if (ret->nodeTab == NULL) {
377 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
378 return(NULL);
379 }
380 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000381 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000382 ret->nodeMax = XML_NODESET_DEFAULT;
383 ret->nodeTab[ret->nodeNr++] = val;
384 }
385 return(ret);
386}
387
388/**
389 * xmlXPathNodeSetAdd:
390 * @cur: the initial node set
391 * @val: a new xmlNodePtr
392 *
393 * add a new xmlNodePtr ot an existing NodeSet
394 */
395void
396xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
397 int i;
398
399 if (val == NULL) return;
400
401 /*
402 * check against doublons
403 */
404 for (i = 0;i < cur->nodeNr;i++)
405 if (cur->nodeTab[i] == val) return;
406
407 /*
408 * grow the nodeTab if needed
409 */
410 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000411 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000412 sizeof(xmlNodePtr));
413 if (cur->nodeTab == NULL) {
414 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
415 return;
416 }
417 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000418 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000419 cur->nodeMax = XML_NODESET_DEFAULT;
420 } else if (cur->nodeNr == cur->nodeMax) {
421 xmlNodePtr *temp;
422
423 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000424 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000425 sizeof(xmlNodePtr));
426 if (temp == NULL) {
427 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
428 return;
429 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000430 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000431 }
432 cur->nodeTab[cur->nodeNr++] = val;
433}
434
435/**
436 * xmlXPathNodeSetMerge:
437 * @val1: the first NodeSet
438 * @val2: the second NodeSet
439 *
440 * Merges two nodesets, all nodes from @val2 are added to @val1
441 *
442 * Returns val1 once extended or NULL in case of error.
443 */
444xmlNodeSetPtr
445xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
446 int i;
447
448 if (val1 == NULL) return(NULL);
449 if (val2 == NULL) return(val1);
450
451 /*
452 * !!!!! this can be optimized a lot, knowing that both
453 * val1 and val2 already have unicity of their values.
454 */
455
456 for (i = 0;i < val2->nodeNr;i++)
457 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
458
459 return(val1);
460}
461
462/**
463 * xmlXPathNodeSetDel:
464 * @cur: the initial node set
465 * @val: an xmlNodePtr
466 *
467 * Removes an xmlNodePtr from an existing NodeSet
468 */
469void
470xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
471 int i;
472
473 if (cur == NULL) return;
474 if (val == NULL) return;
475
476 /*
477 * check against doublons
478 */
479 for (i = 0;i < cur->nodeNr;i++)
480 if (cur->nodeTab[i] == val) break;
481
482 if (i >= cur->nodeNr) {
483#ifdef DEBUG
484 fprintf(xmlXPathDebug,
485 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
486 val->name);
487#endif
488 return;
489 }
490 cur->nodeNr--;
491 for (;i < cur->nodeNr;i++)
492 cur->nodeTab[i] = cur->nodeTab[i + 1];
493 cur->nodeTab[cur->nodeNr] = NULL;
494}
495
496/**
497 * xmlXPathNodeSetRemove:
498 * @cur: the initial node set
499 * @val: the index to remove
500 *
501 * Removes an entry from an existing NodeSet list.
502 */
503void
504xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
505 if (cur == NULL) return;
506 if (val >= cur->nodeNr) return;
507 cur->nodeNr--;
508 for (;val < cur->nodeNr;val++)
509 cur->nodeTab[val] = cur->nodeTab[val + 1];
510 cur->nodeTab[cur->nodeNr] = NULL;
511}
512
513/**
514 * xmlXPathFreeNodeSet:
515 * @obj: the xmlNodeSetPtr to free
516 *
517 * Free the NodeSet compound (not the actual nodes !).
518 */
519void
520xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
521 if (obj == NULL) return;
522 if (obj->nodeTab != NULL) {
523#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000524 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000525#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000526 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000527 }
528#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000529 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000530#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000531 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000532}
533
Daniel Veillardb96e6431999-08-29 21:02:19 +0000534#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000535/**
536 * xmlXPathDebugNodeSet:
537 * @output: a FILE * for the output
538 * @obj: the xmlNodeSetPtr to free
539 *
540 * Quick display of a NodeSet
541 */
542void
543xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
544 int i;
545
546 if (output == NULL) output = xmlXPathDebug;
547 if (obj == NULL) {
548 fprintf(output, "NodeSet == NULL !\n");
549 return;
550 }
551 if (obj->nodeNr == 0) {
552 fprintf(output, "NodeSet is empty\n");
553 return;
554 }
555 if (obj->nodeTab == NULL) {
556 fprintf(output, " nodeTab == NULL !\n");
557 return;
558 }
559 for (i = 0; i < obj->nodeNr; i++) {
560 if (obj->nodeTab[i] == NULL) {
561 fprintf(output, " NULL !\n");
562 return;
563 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000564 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
565 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000566 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,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000598 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000599 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 Veillarddd6b3671999-09-23 22:19:22 +0000658 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000659 *
660 * Create a new xmlXPathObjectPtr of type string and of value @val
661 *
662 * Returns the newly created object.
663 */
664xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000665xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000666 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/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000751 * xmlXPathFreeNodeSetList:
752 * @obj: an existing NodeSetList object
753 *
754 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
755 * the list contrary to xmlXPathFreeObject().
756 */
757void
758xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
759 if (obj == NULL) return;
760#ifdef DEBUG
761 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
762#endif
763 xmlFree(obj);
764}
765
766/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000767 * xmlXPathFreeObject:
768 * @obj: the object to free
769 *
770 * Free up an xmlXPathObjectPtr object.
771 */
772void
773xmlXPathFreeObject(xmlXPathObjectPtr obj) {
774 if (obj == NULL) return;
775 if (obj->nodesetval != NULL)
776 xmlXPathFreeNodeSet(obj->nodesetval);
777 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000778 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000779#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000780 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000781#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000782 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000783}
784
785/************************************************************************
786 * *
787 * Routines to handle XPath contexts *
788 * *
789 ************************************************************************/
790
791/**
792 * xmlXPathNewContext:
793 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000794 *
795 * Create a new xmlXPathContext
796 *
797 * Returns the xmlXPathContext just allocated.
798 */
799xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000800xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000801 xmlXPathContextPtr ret;
802
Daniel Veillard6454aec1999-09-02 22:04:43 +0000803 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000804 if (ret == NULL) {
805 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
806 return(NULL);
807 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000808 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000809 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000810 /***********
811 ret->node = (xmlNodePtr) doc;
812 ret->nodelist = xmlXPathNodeSetCreate(ret->node);
813 ***********/
814 ret->node = NULL;
815 ret->nodelist = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000816
817 ret->nb_variables = 0;
818 ret->max_variables = 0;
819 ret->variables = NULL;
820
821 ret->nb_types = 0;
822 ret->max_types = 0;
823 ret->types = NULL;
824
825 ret->nb_funcs = 0;
826 ret->max_funcs = 0;
827 ret->funcs = NULL;
828
829 ret->nb_axis = 0;
830 ret->max_axis = 0;
831 ret->axis = NULL;
832
Daniel Veillardb96e6431999-08-29 21:02:19 +0000833 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000834 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000835 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000836 return(ret);
837}
838
839/**
840 * xmlXPathFreeContext:
841 * @ctxt: the context to free
842 *
843 * Free up an xmlXPathContext
844 */
845void
846xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000847 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000848 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000849
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000850 /***********
851 if (ctxt->nodelist != NULL)
852 xmlXPathFreeNodeSet(ctxt->nodelist);
853 ***********/
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000854#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000855 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000856#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000857 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000858}
859
860/************************************************************************
861 * *
862 * Routines to handle XPath parser contexts *
863 * *
864 ************************************************************************/
865
866#define CHECK_CTXT \
867 if (ctxt == NULL) { \
868 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
869 __FILE__, __LINE__); \
870 } \
871
872
873#define CHECK_CONTEXT \
874 if (ctxt == NULL) { \
875 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
876 __FILE__, __LINE__); \
877 } \
878 if (ctxt->doc == NULL) { \
879 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
880 __FILE__, __LINE__); \
881 } \
882 if (ctxt->doc->root == NULL) { \
883 fprintf(xmlXPathDebug, \
884 "%s:%d Internal error: document without root\n", \
885 __FILE__, __LINE__); \
886 } \
887
888
889/**
890 * xmlXPathNewParserContext:
891 * @str: the XPath expression
892 * @ctxt: the XPath context
893 *
894 * Create a new xmlXPathParserContext
895 *
896 * Returns the xmlXPathParserContext just allocated.
897 */
898xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000899xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000900 xmlXPathParserContextPtr ret;
901
Daniel Veillard6454aec1999-09-02 22:04:43 +0000902 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000903 if (ret == NULL) {
904 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
905 return(NULL);
906 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000907 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000908 ret->cur = ret->base = str;
909 ret->context = ctxt;
910
911 /* Allocate the value stack */
912 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000913 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000914 ret->valueNr = 0;
915 ret->valueMax = 10;
916 ret->value = NULL;
917 return(ret);
918}
919
920/**
921 * xmlXPathFreeParserContext:
922 * @ctxt: the context to free
923 *
924 * Free up an xmlXPathParserContext
925 */
926void
927xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
928 if (ctxt->valueTab != NULL) {
929#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000930 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000931#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000932 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000933 }
934#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000935 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000936#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000937 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000938}
939
940/************************************************************************
941 * *
942 * The implicit core function library *
943 * *
944 ************************************************************************/
945
946/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000947 * Auto-pop and cast to a number
948 */
949void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
950
951#define CHECK_ARITY(x) \
952 if (nargs != (x)) { \
953 ERROR(XPATH_INVALID_ARITY); \
954 } \
955
956
957#define POP_FLOAT \
958 arg = valuePop(ctxt); \
959 if (arg == NULL) { \
960 ERROR(XPATH_INVALID_OPERAND); \
961 } \
962 if (arg->type != XPATH_NUMBER) { \
963 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000964 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000965 arg = valuePop(ctxt); \
966 }
967
968/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000969 * xmlXPathEqualNodeSetString
970 * @arg: the nodeset object argument
971 * @str: the string to compare to.
972 *
973 * Implement the equal operation on XPath objects content: @arg1 == @arg2
974 * If one object to be compared is a node-set and the other is a string,
975 * then the comparison will be true if and only if there is a node in
976 * the node-set such that the result of performing the comparison on the
977 * string-value of the node and the other string is true.
978 *
979 * Returns 0 or 1 depending on the results of the test.
980 */
981int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000982xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000983 int i;
984 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000985 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000986
987 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
988 return(0);
989 ns = arg->nodesetval;
990 for (i = 0;i < ns->nodeNr;i++) {
991 str2 = xmlNodeGetContent(ns->nodeTab[i]);
992 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000993 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000994 return(1);
995 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000996 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000997 }
998 return(0);
999}
1000
1001/**
1002 * xmlXPathEqualNodeSetFloat
1003 * @arg: the nodeset object argument
1004 * @f: the float to compare to
1005 *
1006 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1007 * If one object to be compared is a node-set and the other is a number,
1008 * then the comparison will be true if and only if there is a node in
1009 * the node-set such that the result of performing the comparison on the
1010 * number to be compared and on the result of converting the string-value
1011 * of that node to a number using the number function is true.
1012 *
1013 * Returns 0 or 1 depending on the results of the test.
1014 */
1015int
1016xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001017 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001018
1019 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1020 return(0);
1021
1022 if (isnan(f))
1023 sprintf(buf, "NaN");
1024 else if (isinf(f) > 0)
1025 sprintf(buf, "+Infinity");
1026 else if (isinf(f) < 0)
1027 sprintf(buf, "-Infinity");
1028 else
1029 sprintf(buf, "%0g", f);
1030
Daniel Veillardb96e6431999-08-29 21:02:19 +00001031 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001032}
1033
1034
1035/**
1036 * xmlXPathEqualNodeSets
1037 * @arg1: first nodeset object argument
1038 * @arg2: second nodeset object argument
1039 *
1040 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1041 * If both objects to be compared are node-sets, then the comparison
1042 * will be true if and only if there is a node in the first node-set and
1043 * a node in the second node-set such that the result of performing the
1044 * comparison on the string-values of the two nodes is true.
1045 *
1046 * (needless to say, this is a costly operation)
1047 *
1048 * Returns 0 or 1 depending on the results of the test.
1049 */
1050int
1051xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1052 int i;
1053 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001054 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001055
1056 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1057 return(0);
1058 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1059 return(0);
1060
1061 ns = arg1->nodesetval;
1062 for (i = 0;i < ns->nodeNr;i++) {
1063 str = xmlNodeGetContent(ns->nodeTab[i]);
1064 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001065 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001066 return(1);
1067 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001068 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001069 }
1070 return(0);
1071}
1072
1073/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001074 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001075 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001076 *
1077 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1078 *
1079 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001080 */
1081int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001082xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1083 xmlXPathObjectPtr arg1, arg2;
1084 int ret = 0;
1085
1086 arg1 = valuePop(ctxt);
1087 if (arg1 == NULL)
1088 ERROR0(XPATH_INVALID_OPERAND);
1089
1090 arg2 = valuePop(ctxt);
1091 if (arg2 == NULL) {
1092 xmlXPathFreeObject(arg1);
1093 ERROR0(XPATH_INVALID_OPERAND);
1094 }
1095
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001096 if (arg1 == arg2) {
1097#ifdef DEBUG_EXPR
1098 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1099#endif
1100 return(1);
1101 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001102
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001103 switch (arg1->type) {
1104 case XPATH_UNDEFINED:
1105#ifdef DEBUG_EXPR
1106 fprintf(xmlXPathDebug, "Equal: undefined\n");
1107#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001108 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001109 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001110 switch (arg2->type) {
1111 case XPATH_UNDEFINED:
1112#ifdef DEBUG_EXPR
1113 fprintf(xmlXPathDebug, "Equal: undefined\n");
1114#endif
1115 break;
1116 case XPATH_NODESET:
1117 ret = xmlXPathEqualNodeSets(arg1, arg2);
1118 break;
1119 case XPATH_BOOLEAN:
1120 if ((arg1->nodesetval == NULL) ||
1121 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1122 else
1123 ret = 1;
1124 ret = (ret == arg2->boolval);
1125 break;
1126 case XPATH_NUMBER:
1127 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1128 break;
1129 case XPATH_STRING:
1130 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1131 break;
1132 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001133 break;
1134 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001135 switch (arg2->type) {
1136 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001137#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001138 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001139#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001140 break;
1141 case XPATH_NODESET:
1142 if ((arg2->nodesetval == NULL) ||
1143 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1144 else
1145 ret = 1;
1146 break;
1147 case XPATH_BOOLEAN:
1148#ifdef DEBUG_EXPR
1149 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1150 arg1->boolval, arg2->boolval);
1151#endif
1152 ret = (arg1->boolval == arg2->boolval);
1153 break;
1154 case XPATH_NUMBER:
1155 if (arg2->floatval) ret = 1;
1156 else ret = 0;
1157 ret = (arg1->boolval == ret);
1158 break;
1159 case XPATH_STRING:
1160 if ((arg2->stringval == NULL) ||
1161 (arg2->stringval[0] == 0)) ret = 0;
1162 else
1163 ret = 1;
1164 ret = (arg1->boolval == ret);
1165 break;
1166 }
1167 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001168 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001169 switch (arg2->type) {
1170 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001171#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001172 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001173#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001174 break;
1175 case XPATH_NODESET:
1176 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1177 break;
1178 case XPATH_BOOLEAN:
1179 if (arg1->floatval) ret = 1;
1180 else ret = 0;
1181 ret = (arg2->boolval == ret);
1182 break;
1183 case XPATH_STRING:
1184 valuePush(ctxt, arg2);
1185 xmlXPathNumberFunction(ctxt, 1);
1186 arg2 = valuePop(ctxt);
1187 /* no break on purpose */
1188 case XPATH_NUMBER:
1189 ret = (arg1->floatval == arg2->floatval);
1190 break;
1191 }
1192 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001193 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001194 switch (arg2->type) {
1195 case XPATH_UNDEFINED:
1196#ifdef DEBUG_EXPR
1197 fprintf(xmlXPathDebug, "Equal: undefined\n");
1198#endif
1199 break;
1200 case XPATH_NODESET:
1201 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1202 break;
1203 case XPATH_BOOLEAN:
1204 if ((arg1->stringval == NULL) ||
1205 (arg1->stringval[0] == 0)) ret = 0;
1206 else
1207 ret = 1;
1208 ret = (arg2->boolval == ret);
1209 break;
1210 case XPATH_STRING:
1211 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1212 break;
1213 case XPATH_NUMBER:
1214 valuePush(ctxt, arg1);
1215 xmlXPathNumberFunction(ctxt, 1);
1216 arg1 = valuePop(ctxt);
1217 ret = (arg1->floatval == arg2->floatval);
1218 break;
1219 }
1220 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001221 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001222 xmlXPathFreeObject(arg1);
1223 xmlXPathFreeObject(arg2);
1224 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001225}
1226
1227/**
1228 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001229 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001230 * @inf: less than (1) or greater than (2)
1231 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001232 *
1233 * Implement the compare operation on XPath objects:
1234 * @arg1 < @arg2 (1, 1, ...
1235 * @arg1 <= @arg2 (1, 0, ...
1236 * @arg1 > @arg2 (0, 1, ...
1237 * @arg1 >= @arg2 (0, 0, ...
1238 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001239 * When neither object to be compared is a node-set and the operator is
1240 * <=, <, >=, >, then the objects are compared by converted both objects
1241 * to numbers and comparing the numbers according to IEEE 754. The <
1242 * comparison will be true if and only if the first number is less than the
1243 * second number. The <= comparison will be true if and only if the first
1244 * number is less than or equal to the second number. The > comparison
1245 * will be true if and only if the first number is greater than the second
1246 * number. The >= comparison will be true if and only if the first number
1247 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001248 */
1249int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001250xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1251 int ret = 0;
1252 xmlXPathObjectPtr arg1, arg2;
1253
1254 arg2 = valuePop(ctxt);
1255 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1256 if (arg2 != NULL)
1257 xmlXPathFreeObject(arg2);
1258 ERROR0(XPATH_INVALID_OPERAND);
1259 }
1260
1261 arg1 = valuePop(ctxt);
1262 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1263 if (arg1 != NULL)
1264 xmlXPathFreeObject(arg1);
1265 xmlXPathFreeObject(arg2);
1266 ERROR0(XPATH_INVALID_OPERAND);
1267 }
1268
1269 if (arg1->type != XPATH_NUMBER) {
1270 valuePush(ctxt, arg1);
1271 xmlXPathNumberFunction(ctxt, 1);
1272 arg1 = valuePop(ctxt);
1273 }
1274 if (arg1->type != XPATH_NUMBER) {
1275 xmlXPathFreeObject(arg1);
1276 xmlXPathFreeObject(arg2);
1277 ERROR0(XPATH_INVALID_OPERAND);
1278 }
1279 if (arg2->type != XPATH_NUMBER) {
1280 valuePush(ctxt, arg2);
1281 xmlXPathNumberFunction(ctxt, 1);
1282 arg2 = valuePop(ctxt);
1283 }
1284 if (arg2->type != XPATH_NUMBER) {
1285 xmlXPathFreeObject(arg1);
1286 xmlXPathFreeObject(arg2);
1287 ERROR0(XPATH_INVALID_OPERAND);
1288 }
1289 /*
1290 * Add tests for infinity and nan
1291 * => feedback on 3.4 for Inf and NaN
1292 */
1293 if (inf && strict)
1294 ret = (arg1->floatval < arg2->floatval);
1295 else if (inf && !strict)
1296 ret = (arg1->floatval <= arg2->floatval);
1297 else if (!inf && strict)
1298 ret = (arg1->floatval > arg2->floatval);
1299 else if (!inf && !strict)
1300 ret = (arg1->floatval >= arg2->floatval);
1301 xmlXPathFreeObject(arg1);
1302 xmlXPathFreeObject(arg2);
1303 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001304}
1305
1306/**
1307 * xmlXPathValueFlipSign:
1308 * @ctxt: the XPath Parser context
1309 *
1310 * Implement the unary - operation on an XPath object
1311 * The numeric operators convert their operands to numbers as if
1312 * by calling the number function.
1313 */
1314void
1315xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1316 xmlXPathObjectPtr arg;
1317
1318 POP_FLOAT
1319 arg->floatval = -arg->floatval;
1320 valuePush(ctxt, arg);
1321}
1322
1323/**
1324 * xmlXPathAddValues:
1325 * @ctxt: the XPath Parser context
1326 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001327 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001328 * The numeric operators convert their operands to numbers as if
1329 * by calling the number function.
1330 */
1331void
1332xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1333 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001334 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001335
1336 POP_FLOAT
1337 val = arg->floatval;
1338 xmlXPathFreeObject(arg);
1339
1340 POP_FLOAT
1341 arg->floatval += val;
1342 valuePush(ctxt, arg);
1343}
1344
1345/**
1346 * xmlXPathSubValues:
1347 * @ctxt: the XPath Parser context
1348 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001349 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001350 * The numeric operators convert their operands to numbers as if
1351 * by calling the number function.
1352 */
1353void
1354xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1355 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001356 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001357
1358 POP_FLOAT
1359 val = arg->floatval;
1360 xmlXPathFreeObject(arg);
1361
1362 POP_FLOAT
1363 arg->floatval -= val;
1364 valuePush(ctxt, arg);
1365}
1366
1367/**
1368 * xmlXPathMultValues:
1369 * @ctxt: the XPath Parser context
1370 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001371 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001372 * The numeric operators convert their operands to numbers as if
1373 * by calling the number function.
1374 */
1375void
1376xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1377 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001378 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001379
1380 POP_FLOAT
1381 val = arg->floatval;
1382 xmlXPathFreeObject(arg);
1383
1384 POP_FLOAT
1385 arg->floatval *= val;
1386 valuePush(ctxt, arg);
1387}
1388
1389/**
1390 * xmlXPathDivValues:
1391 * @ctxt: the XPath Parser context
1392 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001393 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001394 * The numeric operators convert their operands to numbers as if
1395 * by calling the number function.
1396 */
1397void
1398xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1399 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001400 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001401
1402 POP_FLOAT
1403 val = arg->floatval;
1404 xmlXPathFreeObject(arg);
1405
1406 POP_FLOAT
1407 arg->floatval /= val;
1408 valuePush(ctxt, arg);
1409}
1410
1411/**
1412 * xmlXPathModValues:
1413 * @ctxt: the XPath Parser context
1414 *
1415 * Implement the div operation on XPath objects: @arg1 / @arg2
1416 * The numeric operators convert their operands to numbers as if
1417 * by calling the number function.
1418 */
1419void
1420xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1421 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001422 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001423
1424 POP_FLOAT
1425 val = arg->floatval;
1426 xmlXPathFreeObject(arg);
1427
1428 POP_FLOAT
1429 arg->floatval /= val;
1430 valuePush(ctxt, arg);
1431}
1432
1433/************************************************************************
1434 * *
1435 * The traversal functions *
1436 * *
1437 ************************************************************************/
1438
1439#define AXIS_ANCESTOR 1
1440#define AXIS_ANCESTOR_OR_SELF 2
1441#define AXIS_ATTRIBUTE 3
1442#define AXIS_CHILD 4
1443#define AXIS_DESCENDANT 5
1444#define AXIS_DESCENDANT_OR_SELF 6
1445#define AXIS_FOLLOWING 7
1446#define AXIS_FOLLOWING_SIBLING 8
1447#define AXIS_NAMESPACE 9
1448#define AXIS_PARENT 10
1449#define AXIS_PRECEDING 11
1450#define AXIS_PRECEDING_SIBLING 12
1451#define AXIS_SELF 13
1452
1453/*
1454 * A traversal function enumerates nodes along an axis.
1455 * Initially it must be called with NULL, and it indicates
1456 * termination on the axis by returning NULL.
1457 */
1458typedef xmlNodePtr (*xmlXPathTraversalFunction)
1459 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1460
1461/**
1462 * mlXPathNextSelf:
1463 * @ctxt: the XPath Parser context
1464 * @cur: the current node in the traversal
1465 *
1466 * Traversal function for the "self" direction
1467 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001468 *
1469 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001470 */
1471xmlNodePtr
1472xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1473 if (cur == NULL)
1474 return(ctxt->context->node);
1475 return(NULL);
1476}
1477
1478/**
1479 * mlXPathNextChild:
1480 * @ctxt: the XPath Parser context
1481 * @cur: the current node in the traversal
1482 *
1483 * Traversal function for the "child" direction
1484 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001485 *
1486 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001487 */
1488xmlNodePtr
1489xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001490 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001491 if (ctxt->context->node == NULL) return(NULL);
1492 switch (ctxt->context->node->type) {
1493 case XML_ELEMENT_NODE:
1494 case XML_TEXT_NODE:
1495 case XML_CDATA_SECTION_NODE:
1496 case XML_ENTITY_REF_NODE:
1497 case XML_ENTITY_NODE:
1498 case XML_PI_NODE:
1499 case XML_COMMENT_NODE:
1500 case XML_NOTATION_NODE:
1501 return(ctxt->context->node->childs);
1502 case XML_ATTRIBUTE_NODE:
1503 return(NULL);
1504 case XML_DOCUMENT_NODE:
1505 case XML_DOCUMENT_TYPE_NODE:
1506 case XML_DOCUMENT_FRAG_NODE:
1507 case XML_HTML_DOCUMENT_NODE:
1508 return(((xmlDocPtr) ctxt->context->node)->root);
1509 }
1510 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001511 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001512 if ((cur->type == XML_DOCUMENT_NODE) ||
1513 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001514 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001515 return(cur->next);
1516}
1517
1518/**
1519 * mlXPathNextDescendant:
1520 * @ctxt: the XPath Parser context
1521 * @cur: the current node in the traversal
1522 *
1523 * Traversal function for the "descendant" direction
1524 * the descendant axis contains the descendants of the context node in document
1525 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001526 *
1527 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001528 */
1529xmlNodePtr
1530xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001531 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001532 if (ctxt->context->node == NULL)
1533 return(NULL);
1534 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1535 return(NULL);
1536
Daniel Veillardb05deb71999-08-10 19:04:08 +00001537 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1538 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001539 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001540 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001541
1542 if (cur->childs != NULL) return(cur->childs);
1543 if (cur->next != NULL) return(cur->next);
1544
1545 do {
1546 cur = cur->parent;
1547 if (cur == NULL) return(NULL);
1548 if (cur == ctxt->context->node) return(NULL);
1549 if (cur->next != NULL) {
1550 cur = cur->next;
1551 return(cur);
1552 }
1553 } while (cur != NULL);
1554 return(cur);
1555}
1556
1557/**
1558 * mlXPathNextDescendantOrSelf:
1559 * @ctxt: the XPath Parser context
1560 * @cur: the current node in the traversal
1561 *
1562 * Traversal function for the "descendant-or-self" direction
1563 * the descendant-or-self axis contains the context node and the descendants
1564 * of the context node in document order; thus the context node is the first
1565 * node on the axis, and the first child of the context node is the second node
1566 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001567 *
1568 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001569 */
1570xmlNodePtr
1571xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001572 if (cur == NULL) {
1573 if (ctxt->context->node == NULL)
1574 return(NULL);
1575 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1576 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001577 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001578 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001579
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001580 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001581}
1582
1583/**
1584 * xmlXPathNextParent:
1585 * @ctxt: the XPath Parser context
1586 * @cur: the current node in the traversal
1587 *
1588 * Traversal function for the "parent" direction
1589 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001590 *
1591 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001592 */
1593xmlNodePtr
1594xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1595 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001596 * the parent of an attribute or namespace node is the element
1597 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001598 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001599 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001600 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001601 if (ctxt->context->node == NULL) return(NULL);
1602 switch (ctxt->context->node->type) {
1603 case XML_ELEMENT_NODE:
1604 case XML_TEXT_NODE:
1605 case XML_CDATA_SECTION_NODE:
1606 case XML_ENTITY_REF_NODE:
1607 case XML_ENTITY_NODE:
1608 case XML_PI_NODE:
1609 case XML_COMMENT_NODE:
1610 case XML_NOTATION_NODE:
1611 if (ctxt->context->node->parent == NULL)
1612 return((xmlNodePtr) ctxt->context->doc);
1613 return(ctxt->context->node->parent);
1614 case XML_ATTRIBUTE_NODE: {
1615 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1616
1617 return(att->node);
1618 }
1619 case XML_DOCUMENT_NODE:
1620 case XML_DOCUMENT_TYPE_NODE:
1621 case XML_DOCUMENT_FRAG_NODE:
1622 case XML_HTML_DOCUMENT_NODE:
1623 return(NULL);
1624 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001625 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001626 return(NULL);
1627}
1628
1629/**
1630 * xmlXPathNextAncestor:
1631 * @ctxt: the XPath Parser context
1632 * @cur: the current node in the traversal
1633 *
1634 * Traversal function for the "ancestor" direction
1635 * the ancestor axis contains the ancestors of the context node; the ancestors
1636 * of the context node consist of the parent of context node and the parent's
1637 * parent and so on; the nodes are ordered in reverse document order; thus the
1638 * parent is the first node on the axis, and the parent's parent is the second
1639 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001640 *
1641 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001642 */
1643xmlNodePtr
1644xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1645 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001646 * the parent of an attribute or namespace node is the element
1647 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001648 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001649 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001650 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001651 if (ctxt->context->node == NULL) return(NULL);
1652 switch (ctxt->context->node->type) {
1653 case XML_ELEMENT_NODE:
1654 case XML_TEXT_NODE:
1655 case XML_CDATA_SECTION_NODE:
1656 case XML_ENTITY_REF_NODE:
1657 case XML_ENTITY_NODE:
1658 case XML_PI_NODE:
1659 case XML_COMMENT_NODE:
1660 case XML_NOTATION_NODE:
1661 if (ctxt->context->node->parent == NULL)
1662 return((xmlNodePtr) ctxt->context->doc);
1663 return(ctxt->context->node->parent);
1664 case XML_ATTRIBUTE_NODE: {
1665 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
1666
1667 return(cur->node);
1668 }
1669 case XML_DOCUMENT_NODE:
1670 case XML_DOCUMENT_TYPE_NODE:
1671 case XML_DOCUMENT_FRAG_NODE:
1672 case XML_HTML_DOCUMENT_NODE:
1673 return(NULL);
1674 }
1675 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001676 }
1677 if (cur == ctxt->context->doc->root)
1678 return((xmlNodePtr) ctxt->context->doc);
1679 if (cur == (xmlNodePtr) ctxt->context->doc)
1680 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001681 switch (cur->type) {
1682 case XML_ELEMENT_NODE:
1683 case XML_TEXT_NODE:
1684 case XML_CDATA_SECTION_NODE:
1685 case XML_ENTITY_REF_NODE:
1686 case XML_ENTITY_NODE:
1687 case XML_PI_NODE:
1688 case XML_COMMENT_NODE:
1689 case XML_NOTATION_NODE:
1690 return(cur->parent);
1691 case XML_ATTRIBUTE_NODE: {
1692 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1693
1694 return(att->node);
1695 }
1696 case XML_DOCUMENT_NODE:
1697 case XML_DOCUMENT_TYPE_NODE:
1698 case XML_DOCUMENT_FRAG_NODE:
1699 case XML_HTML_DOCUMENT_NODE:
1700 return(NULL);
1701 }
1702 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001703}
1704
1705/**
1706 * xmlXPathNextAncestorOrSelf:
1707 * @ctxt: the XPath Parser context
1708 * @cur: the current node in the traversal
1709 *
1710 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001711 * he ancestor-or-self axis contains the context node and ancestors of
1712 * the context node in reverse document order; thus the context node is
1713 * the first node on the axis, and the context node's parent the second;
1714 * parent here is defined the same as with the parent axis.
1715 *
1716 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001717 */
1718xmlNodePtr
1719xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001720 if (cur == NULL)
1721 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001722 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001723}
1724
1725/**
1726 * xmlXPathNextFollowingSibling:
1727 * @ctxt: the XPath Parser context
1728 * @cur: the current node in the traversal
1729 *
1730 * Traversal function for the "following-sibling" direction
1731 * The following-sibling axis contains the following siblings of the context
1732 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001733 *
1734 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001735 */
1736xmlNodePtr
1737xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001738 if (cur == (xmlNodePtr) ctxt->context->doc)
1739 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001740 if (cur == NULL)
1741 return(ctxt->context->node->next);
1742 return(cur->next);
1743}
1744
1745/**
1746 * xmlXPathNextPrecedingSibling:
1747 * @ctxt: the XPath Parser context
1748 * @cur: the current node in the traversal
1749 *
1750 * Traversal function for the "preceding-sibling" direction
1751 * The preceding-sibling axis contains the preceding siblings of the context
1752 * node in reverse document order; the first preceding sibling is first on the
1753 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001754 *
1755 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001756 */
1757xmlNodePtr
1758xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001759 if (cur == (xmlNodePtr) ctxt->context->doc)
1760 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001761 if (cur == NULL)
1762 return(ctxt->context->node->prev);
1763 return(cur->prev);
1764}
1765
1766/**
1767 * xmlXPathNextFollowing:
1768 * @ctxt: the XPath Parser context
1769 * @cur: the current node in the traversal
1770 *
1771 * Traversal function for the "following" direction
1772 * The following axis contains all nodes in the same document as the context
1773 * node that are after the context node in document order, excluding any
1774 * descendants and excluding attribute nodes and namespace nodes; the nodes
1775 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001776 *
1777 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001778 */
1779xmlNodePtr
1780xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001781 if (cur == (xmlNodePtr) ctxt->context->doc)
1782 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001783 if (cur == NULL)
1784 return(ctxt->context->node->next);; /* !!!!!!!!! */
1785 if (cur->childs != NULL) return(cur->childs);
1786 if (cur->next != NULL) return(cur->next);
1787
1788 do {
1789 cur = cur->parent;
1790 if (cur == NULL) return(NULL);
1791 if (cur == ctxt->context->doc->root) return(NULL);
1792 if (cur->next != NULL) {
1793 cur = cur->next;
1794 return(cur);
1795 }
1796 } while (cur != NULL);
1797 return(cur);
1798}
1799
1800/**
1801 * xmlXPathNextPreceding:
1802 * @ctxt: the XPath Parser context
1803 * @cur: the current node in the traversal
1804 *
1805 * Traversal function for the "preceding" direction
1806 * the preceding axis contains all nodes in the same document as the context
1807 * node that are before the context node in document order, excluding any
1808 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1809 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001810 *
1811 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001812 */
1813xmlNodePtr
1814xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001815 if (cur == (xmlNodePtr) ctxt->context->doc)
1816 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001817 if (cur == NULL)
1818 return(ctxt->context->node->prev); /* !!!!!!!!! */
1819 if (cur->last != NULL) return(cur->last);
1820 if (cur->prev != NULL) return(cur->prev);
1821
1822 do {
1823 cur = cur->parent;
1824 if (cur == NULL) return(NULL);
1825 if (cur == ctxt->context->doc->root) return(NULL);
1826 if (cur->prev != NULL) {
1827 cur = cur->prev;
1828 return(cur);
1829 }
1830 } while (cur != NULL);
1831 return(cur);
1832}
1833
1834/**
1835 * xmlXPathNextNamespace:
1836 * @ctxt: the XPath Parser context
1837 * @cur: the current attribute in the traversal
1838 *
1839 * Traversal function for the "namespace" direction
1840 * the namespace axis contains the namespace nodes of the context node;
1841 * the order of nodes on this axis is implementation-defined; the axis will
1842 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001843 *
1844 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001845 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001846xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001847xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001848 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1849 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001850 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001851 ctxt->context->namespaces =
1852 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1853 if (ctxt->context->namespaces == NULL) return(NULL);
1854 ctxt->context->nsNr = 0;
1855 }
1856 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001857}
1858
1859/**
1860 * xmlXPathNextAttribute:
1861 * @ctxt: the XPath Parser context
1862 * @cur: the current attribute in the traversal
1863 *
1864 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001865 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001866 *
1867 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001868 */
1869xmlAttrPtr
1870xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001871 if (cur == NULL) {
1872 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1873 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001874 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001875 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001876 return(cur->next);
1877}
1878
1879/************************************************************************
1880 * *
1881 * NodeTest Functions *
1882 * *
1883 ************************************************************************/
1884
1885#define NODE_TEST_NONE 0
1886#define NODE_TEST_TYPE 1
1887#define NODE_TEST_PI 2
1888#define NODE_TEST_ALL 3
1889#define NODE_TEST_NS 4
1890#define NODE_TEST_NAME 5
1891
1892#define NODE_TYPE_COMMENT 50
1893#define NODE_TYPE_TEXT 51
1894#define NODE_TYPE_PI 52
1895#define NODE_TYPE_NODE 53
1896
1897#define IS_FUNCTION 200
1898
1899/**
1900 * xmlXPathNodeCollectAndTest:
1901 * @ctxt: the XPath Parser context
1902 * @cur: the current node to test
1903 *
1904 * This is the function implementing a step: based on the current list
1905 * of nodes, it builds up a new list, looking at all nodes under that
1906 * axis and selecting them.
1907 *
1908 * Returns the new NodeSet resulting from the search.
1909 */
1910xmlNodeSetPtr
1911xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001912 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001913#ifdef DEBUG_STEP
1914 int n = 0, t = 0;
1915#endif
1916 int i;
1917 xmlNodeSetPtr ret;
1918 xmlXPathTraversalFunction next = NULL;
1919 xmlNodePtr cur = NULL;
1920
1921 if (ctxt->context->nodelist == NULL) {
1922 if (ctxt->context->node == NULL) {
1923 fprintf(xmlXPathDebug,
1924 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1925 __FILE__, __LINE__);
1926 return(NULL);
1927 }
1928 STRANGE
1929 return(NULL);
1930 }
1931#ifdef DEBUG_STEP
1932 fprintf(xmlXPathDebug, "new step : ");
1933#endif
1934 switch (axis) {
1935 case AXIS_ANCESTOR:
1936#ifdef DEBUG_STEP
1937 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1938#endif
1939 next = xmlXPathNextAncestor; break;
1940 case AXIS_ANCESTOR_OR_SELF:
1941#ifdef DEBUG_STEP
1942 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1943#endif
1944 next = xmlXPathNextAncestorOrSelf; break;
1945 case AXIS_ATTRIBUTE:
1946#ifdef DEBUG_STEP
1947 fprintf(xmlXPathDebug, "axis 'attributes' ");
1948#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001949 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001950 break;
1951 case AXIS_CHILD:
1952#ifdef DEBUG_STEP
1953 fprintf(xmlXPathDebug, "axis 'child' ");
1954#endif
1955 next = xmlXPathNextChild; break;
1956 case AXIS_DESCENDANT:
1957#ifdef DEBUG_STEP
1958 fprintf(xmlXPathDebug, "axis 'descendant' ");
1959#endif
1960 next = xmlXPathNextDescendant; break;
1961 case AXIS_DESCENDANT_OR_SELF:
1962#ifdef DEBUG_STEP
1963 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1964#endif
1965 next = xmlXPathNextDescendantOrSelf; break;
1966 case AXIS_FOLLOWING:
1967#ifdef DEBUG_STEP
1968 fprintf(xmlXPathDebug, "axis 'following' ");
1969#endif
1970 next = xmlXPathNextFollowing; break;
1971 case AXIS_FOLLOWING_SIBLING:
1972#ifdef DEBUG_STEP
1973 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1974#endif
1975 next = xmlXPathNextFollowingSibling; break;
1976 case AXIS_NAMESPACE:
1977#ifdef DEBUG_STEP
1978 fprintf(xmlXPathDebug, "axis 'namespace' ");
1979#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001980 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001981 break;
1982 case AXIS_PARENT:
1983#ifdef DEBUG_STEP
1984 fprintf(xmlXPathDebug, "axis 'parent' ");
1985#endif
1986 next = xmlXPathNextParent; break;
1987 case AXIS_PRECEDING:
1988#ifdef DEBUG_STEP
1989 fprintf(xmlXPathDebug, "axis 'preceding' ");
1990#endif
1991 next = xmlXPathNextPreceding; break;
1992 case AXIS_PRECEDING_SIBLING:
1993#ifdef DEBUG_STEP
1994 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1995#endif
1996 next = xmlXPathNextPrecedingSibling; break;
1997 case AXIS_SELF:
1998#ifdef DEBUG_STEP
1999 fprintf(xmlXPathDebug, "axis 'self' ");
2000#endif
2001 next = xmlXPathNextSelf; break;
2002 }
2003 if (next == NULL) return(NULL);
2004 ret = xmlXPathNodeSetCreate(NULL);
2005#ifdef DEBUG_STEP
2006 fprintf(xmlXPathDebug, " context contains %d nodes\n",
2007 ctxt->context->nodelist->nodeNr);
2008 switch (test) {
2009 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002010 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002011 break;
2012 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002013 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002014 break;
2015 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002016 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002017 break;
2018 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002019 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002020 break;
2021 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002022 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002023 prefix);
2024 break;
2025 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002026 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002027 if (prefix != NULL)
2028 fprintf(xmlXPathDebug, " with namespace %s\n",
2029 prefix);
2030 break;
2031 }
2032 fprintf(xmlXPathDebug, "Testing : ");
2033#endif
2034 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
2035 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
2036
2037 cur = NULL;
2038 do {
2039 cur = next(ctxt, cur);
2040 if (cur == NULL) break;
2041#ifdef DEBUG_STEP
2042 t++;
2043 fprintf(xmlXPathDebug, " %s", cur->name);
2044#endif
2045 switch (test) {
2046 case NODE_TEST_NONE:
2047 STRANGE
2048 return(NULL);
2049 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002050 if ((cur->type == type) ||
2051 ((type == XML_ELEMENT_NODE) &&
2052 ((cur->type == XML_DOCUMENT_NODE) ||
2053 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002054#ifdef DEBUG_STEP
2055 n++;
2056#endif
2057 xmlXPathNodeSetAdd(ret, cur);
2058 }
2059 break;
2060 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002061 if (cur->type == XML_PI_NODE) {
2062 if ((name != NULL) &&
2063 (xmlStrcmp(name, cur->name)))
2064 break;
2065#ifdef DEBUG_STEP
2066 n++;
2067#endif
2068 xmlXPathNodeSetAdd(ret, cur);
2069 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002070 break;
2071 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002072 if ((cur->type == XML_ELEMENT_NODE) ||
2073 (cur->type == XML_ATTRIBUTE_NODE)) {
2074 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002075#ifdef DEBUG_STEP
2076 n++;
2077#endif
2078 xmlXPathNodeSetAdd(ret, cur);
2079 }
2080 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002081 case NODE_TEST_NS: {
2082 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002083 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002084 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002085 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002086 switch (cur->type) {
2087 case XML_ELEMENT_NODE:
2088 if (!xmlStrcmp(name, cur->name) &&
2089 (((prefix == NULL) ||
2090 ((cur->ns != NULL) &&
2091 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002092#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002093 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002094#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002095 xmlXPathNodeSetAdd(ret, cur);
2096 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002097 break;
2098 case XML_ATTRIBUTE_NODE: {
2099 xmlAttrPtr attr = (xmlAttrPtr) cur;
2100 if (!xmlStrcmp(name, attr->name)) {
2101#ifdef DEBUG_STEP
2102 n++;
2103#endif
2104 xmlXPathNodeSetAdd(ret, cur);
2105 }
2106 break;
2107 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002108 default:
2109 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002110 }
2111 break;
2112
2113 }
2114 } while (cur != NULL);
2115 }
2116#ifdef DEBUG_STEP
2117 fprintf(xmlXPathDebug,
2118 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2119#endif
2120 return(ret);
2121}
2122
2123
2124/************************************************************************
2125 * *
2126 * Implicit tree core function library *
2127 * *
2128 ************************************************************************/
2129
2130/**
2131 * xmlXPathRoot:
2132 * @ctxt: the XPath Parser context
2133 *
2134 * Initialize the context to the root of the document
2135 */
2136void
2137xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2138 if (ctxt->context->nodelist != NULL)
2139 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002140 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2141 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002142}
2143
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002144/************************************************************************
2145 * *
2146 * The explicit core function library *
2147 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2148 * *
2149 ************************************************************************/
2150
2151
2152/**
2153 * xmlXPathLastFunction:
2154 * @ctxt: the XPath Parser context
2155 *
2156 * Implement the last() XPath function
2157 * The last function returns the number of nodes in the context node list.
2158 */
2159void
2160xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2161 CHECK_ARITY(0);
2162 if ((ctxt->context->nodelist == NULL) ||
2163 (ctxt->context->node == NULL) ||
2164 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002165 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002166 } else {
2167 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002168 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002169 }
2170}
2171
2172/**
2173 * xmlXPathPositionFunction:
2174 * @ctxt: the XPath Parser context
2175 *
2176 * Implement the position() XPath function
2177 * The position function returns the position of the context node in the
2178 * context node list. The first position is 1, and so the last positionr
2179 * will be equal to last().
2180 */
2181void
2182xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2183 int i;
2184
2185 CHECK_ARITY(0);
2186 if ((ctxt->context->nodelist == NULL) ||
2187 (ctxt->context->node == NULL) ||
2188 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002189 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002190 }
2191 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2192 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002193 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002194 return;
2195 }
2196 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002197 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002198}
2199
2200/**
2201 * xmlXPathCountFunction:
2202 * @ctxt: the XPath Parser context
2203 *
2204 * Implement the count() XPath function
2205 */
2206void
2207xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2208 xmlXPathObjectPtr cur;
2209
2210 CHECK_ARITY(1);
2211 CHECK_TYPE(XPATH_NODESET);
2212 cur = valuePop(ctxt);
2213
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002214 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002215 xmlXPathFreeObject(cur);
2216}
2217
2218/**
2219 * xmlXPathIdFunction:
2220 * @ctxt: the XPath Parser context
2221 *
2222 * Implement the id() XPath function
2223 * The id function selects elements by their unique ID
2224 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2225 * then the result is the union of the result of applying id to the
2226 * string value of each of the nodes in the argument node-set. When the
2227 * argument to id is of any other type, the argument is converted to a
2228 * string as if by a call to the string function; the string is split
2229 * into a whitespace-separated list of tokens (whitespace is any sequence
2230 * of characters matching the production S); the result is a node-set
2231 * containing the elements in the same document as the context node that
2232 * have a unique ID equal to any of the tokens in the list.
2233 */
2234void
2235xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002236 const xmlChar *tokens;
2237 const xmlChar *cur;
2238 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002239 xmlAttrPtr attr;
2240 xmlNodePtr elem = NULL;
2241 xmlXPathObjectPtr ret, obj;
2242
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002243 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002244 obj = valuePop(ctxt);
2245 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2246 if (obj->type == XPATH_NODESET) {
2247 TODO /* ID function in case of NodeSet */
2248 }
2249 if (obj->type != XPATH_STRING) {
2250 valuePush(ctxt, obj);
2251 xmlXPathStringFunction(ctxt, 1);
2252 obj = valuePop(ctxt);
2253 if (obj->type != XPATH_STRING) {
2254 xmlXPathFreeObject(obj);
2255 return;
2256 }
2257 }
2258 tokens = obj->stringval;
2259
2260 ret = xmlXPathNewNodeSet(NULL);
2261 valuePush(ctxt, ret);
2262 if (tokens == NULL) {
2263 xmlXPathFreeObject(obj);
2264 return;
2265 }
2266
2267 cur = tokens;
2268
2269 while (IS_BLANK(*cur)) cur++;
2270 while (*cur != 0) {
2271 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2272 (*cur == '.') || (*cur == '-') ||
2273 (*cur == '_') || (*cur == ':') ||
2274 (IS_COMBINING(*cur)) ||
2275 (IS_EXTENDER(*cur)))
2276 cur++;
2277
2278 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2279
2280 ID = xmlStrndup(tokens, cur - tokens);
2281 attr = xmlGetID(ctxt->context->doc, ID);
2282 if (attr != NULL) {
2283 elem = attr->node;
2284 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2285 }
2286 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002287 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002288
2289 while (IS_BLANK(*cur)) cur++;
2290 tokens = cur;
2291 }
2292 xmlXPathFreeObject(obj);
2293 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002294}
2295
2296/**
2297 * xmlXPathLocalPartFunction:
2298 * @ctxt: the XPath Parser context
2299 *
2300 * Implement the local-part() XPath function
2301 * The local-part function returns a string containing the local part
2302 * of the name of the node in the argument node-set that is first in
2303 * document order. If the node-set is empty or the first node has no
2304 * name, an empty string is returned. If the argument is omitted it
2305 * defaults to the context node.
2306 */
2307void
2308xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2309 xmlXPathObjectPtr cur;
2310
2311 CHECK_ARITY(1);
2312 CHECK_TYPE(XPATH_NODESET);
2313 cur = valuePop(ctxt);
2314
2315 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002316 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002317 } else {
2318 int i = 0; /* Should be first in document order !!!!! */
2319 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2320 }
2321 xmlXPathFreeObject(cur);
2322}
2323
2324/**
2325 * xmlXPathNamespaceFunction:
2326 * @ctxt: the XPath Parser context
2327 *
2328 * Implement the namespace() XPath function
2329 * The namespace function returns a string containing the namespace URI
2330 * of the expanded name of the node in the argument node-set that is
2331 * first in document order. If the node-set is empty, the first node has
2332 * no name, or the expanded name has no namespace URI, an empty string
2333 * is returned. If the argument is omitted it defaults to the context node.
2334 */
2335void
2336xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2337 xmlXPathObjectPtr cur;
2338
Daniel Veillardb96e6431999-08-29 21:02:19 +00002339 if (nargs == 0) {
2340 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2341 nargs = 1;
2342 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002343 CHECK_ARITY(1);
2344 CHECK_TYPE(XPATH_NODESET);
2345 cur = valuePop(ctxt);
2346
2347 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002348 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002349 } else {
2350 int i = 0; /* Should be first in document order !!!!! */
2351
2352 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002353 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002354 else
2355 valuePush(ctxt, xmlXPathNewString(
2356 cur->nodesetval->nodeTab[i]->ns->href));
2357 }
2358 xmlXPathFreeObject(cur);
2359}
2360
2361/**
2362 * xmlXPathNameFunction:
2363 * @ctxt: the XPath Parser context
2364 *
2365 * Implement the name() XPath function
2366 * The name function returns a string containing a QName representing
2367 * the name of the node in the argument node-set that is first in documenti
2368 * order. The QName must represent the name with respect to the namespace
2369 * declarations in effect on the node whose name is being represented.
2370 * Typically, this will be the form in which the name occurred in the XML
2371 * source. This need not be the case if there are namespace declarations
2372 * in effect on the node that associate multiple prefixes with the same
2373 * namespace. However, an implementation may include information about
2374 * the original prefix in its representation of nodes; in this case, an
2375 * implementation can ensure that the returned string is always the same
2376 * as the QName used in the XML source. If the argument it omitted it
2377 * defaults to the context node.
2378 * Libxml keep the original prefix so the "real qualified name" used is
2379 * returned.
2380 */
2381void
2382xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2383 xmlXPathObjectPtr cur;
2384
2385 CHECK_ARITY(1);
2386 CHECK_TYPE(XPATH_NODESET);
2387 cur = valuePop(ctxt);
2388
2389 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002390 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002391 } else {
2392 int i = 0; /* Should be first in document order !!!!! */
2393
2394 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2395 valuePush(ctxt, xmlXPathNewString(
2396 cur->nodesetval->nodeTab[i]->name));
2397
2398 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002399 char name[2000];
2400 sprintf(name, "%s:%s",
2401 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2402 (char *) cur->nodesetval->nodeTab[i]->name);
2403 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002404 }
2405 }
2406 xmlXPathFreeObject(cur);
2407}
2408
2409/**
2410 * xmlXPathStringFunction:
2411 * @ctxt: the XPath Parser context
2412 *
2413 * Implement the string() XPath function
2414 * he string function converts an object to a string as follows:
2415 * - A node-set is converted to a string by returning the value of
2416 * the node in the node-set that is first in document order.
2417 * If the node-set is empty, an empty string is returned.
2418 * - A number is converted to a string as follows
2419 * + NaN is converted to the string NaN
2420 * + positive zero is converted to the string 0
2421 * + negative zero is converted to the string 0
2422 * + positive infinity is converted to the string Infinity
2423 * + negative infinity is converted to the string -Infinity
2424 * + if the number is an integer, the number is represented in
2425 * decimal form as a Number with no decimal point and no leading
2426 * zeros, preceded by a minus sign (-) if the number is negative
2427 * + otherwise, the number is represented in decimal form as a
2428 * Number including a decimal point with at least one digit
2429 * before the decimal point and at least one digit after the
2430 * decimal point, preceded by a minus sign (-) if the number
2431 * is negative; there must be no leading zeros before the decimal
2432 * point apart possibly from the one required digit immediatelyi
2433 * before the decimal point; beyond the one required digit
2434 * after the decimal point there must be as many, but only as
2435 * many, more digits as are needed to uniquely distinguish the
2436 * number from all other IEEE 754 numeric values.
2437 * - The boolean false value is converted to the string false.
2438 * The boolean true value is converted to the string true.
2439 */
2440void
2441xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2442 xmlXPathObjectPtr cur;
2443
2444 CHECK_ARITY(1);
2445 cur = valuePop(ctxt);
2446 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2447 switch (cur->type) {
2448 case XPATH_NODESET:
2449 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002450 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002451 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002452 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002453 int i = 0; /* Should be first in document order !!!!! */
2454 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2455 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002456 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002457 }
2458 xmlXPathFreeObject(cur);
2459 return;
2460 case XPATH_STRING:
2461 valuePush(ctxt, cur);
2462 return;
2463 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002464 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2465 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002466 xmlXPathFreeObject(cur);
2467 return;
2468 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002469 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002470
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002471 if (isnan(cur->floatval))
2472 sprintf(buf, "NaN");
2473 else if (isinf(cur->floatval) > 0)
2474 sprintf(buf, "+Infinity");
2475 else if (isinf(cur->floatval) < 0)
2476 sprintf(buf, "-Infinity");
2477 else
2478 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002479 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002480 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002481 return;
2482 }
2483 }
2484 STRANGE
2485}
2486
2487/**
2488 * xmlXPathStringLengthFunction:
2489 * @ctxt: the XPath Parser context
2490 *
2491 * Implement the string-length() XPath function
2492 * The string-length returns the number of characters in the string
2493 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2494 * the context node converted to a string, in other words the value
2495 * of the context node.
2496 */
2497void
2498xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2499 xmlXPathObjectPtr cur;
2500
2501 if (nargs == 0) {
2502 if (ctxt->context->node == NULL) {
2503 valuePush(ctxt, xmlXPathNewFloat(0));
2504 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002505 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002506
2507 content = xmlNodeGetContent(ctxt->context->node);
2508 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002509 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002510 }
2511 return;
2512 }
2513 CHECK_ARITY(1);
2514 CHECK_TYPE(XPATH_STRING);
2515 cur = valuePop(ctxt);
2516 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2517 xmlXPathFreeObject(cur);
2518}
2519
2520/**
2521 * xmlXPathConcatFunction:
2522 * @ctxt: the XPath Parser context
2523 *
2524 * Implement the concat() XPath function
2525 * The concat function returns the concatenation of its arguments.
2526 */
2527void
2528xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2529 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002530 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002531
2532 if (nargs < 2) {
2533 CHECK_ARITY(2);
2534 }
2535
2536 cur = valuePop(ctxt);
2537 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2538 xmlXPathFreeObject(cur);
2539 return;
2540 }
2541 nargs--;
2542
2543 while (nargs > 0) {
2544 new = valuePop(ctxt);
2545 if ((new == NULL) || (new->type != XPATH_STRING)) {
2546 xmlXPathFreeObject(new);
2547 xmlXPathFreeObject(cur);
2548 ERROR(XPATH_INVALID_TYPE);
2549 }
2550 tmp = xmlStrcat(new->stringval, cur->stringval);
2551 new->stringval = cur->stringval;
2552 cur->stringval = tmp;
2553
2554 xmlXPathFreeObject(new);
2555 nargs--;
2556 }
2557 valuePush(ctxt, cur);
2558}
2559
2560/**
2561 * xmlXPathContainsFunction:
2562 * @ctxt: the XPath Parser context
2563 *
2564 * Implement the contains() XPath function
2565 * The contains function returns true if the first argument string
2566 * contains the second argument string, and otherwise returns false.
2567 */
2568void
2569xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2570 xmlXPathObjectPtr hay, needle;
2571
2572 CHECK_ARITY(2);
2573 CHECK_TYPE(XPATH_STRING);
2574 needle = valuePop(ctxt);
2575 hay = valuePop(ctxt);
2576 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2577 xmlXPathFreeObject(hay);
2578 xmlXPathFreeObject(needle);
2579 ERROR(XPATH_INVALID_TYPE);
2580 }
2581 if (xmlStrstr(hay->stringval, needle->stringval))
2582 valuePush(ctxt, xmlXPathNewBoolean(1));
2583 else
2584 valuePush(ctxt, xmlXPathNewBoolean(0));
2585 xmlXPathFreeObject(hay);
2586 xmlXPathFreeObject(needle);
2587}
2588
2589/**
2590 * xmlXPathStartsWithFunction:
2591 * @ctxt: the XPath Parser context
2592 *
2593 * Implement the starts-with() XPath function
2594 * The starts-with function returns true if the first argument string
2595 * starts with the second argument string, and otherwise returns false.
2596 */
2597void
2598xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2599 xmlXPathObjectPtr hay, needle;
2600 int n;
2601
2602 CHECK_ARITY(2);
2603 CHECK_TYPE(XPATH_STRING);
2604 needle = valuePop(ctxt);
2605 hay = valuePop(ctxt);
2606 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2607 xmlXPathFreeObject(hay);
2608 xmlXPathFreeObject(needle);
2609 ERROR(XPATH_INVALID_TYPE);
2610 }
2611 n = xmlStrlen(needle->stringval);
2612 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2613 valuePush(ctxt, xmlXPathNewBoolean(0));
2614 else
2615 valuePush(ctxt, xmlXPathNewBoolean(1));
2616 xmlXPathFreeObject(hay);
2617 xmlXPathFreeObject(needle);
2618}
2619
2620/**
2621 * xmlXPathSubstringFunction:
2622 * @ctxt: the XPath Parser context
2623 *
2624 * Implement the substring() XPath function
2625 * The substring function returns the substring of the first argument
2626 * starting at the position specified in the second argument with
2627 * length specified in the third argument. For example,
2628 * substring("12345",2,3) returns "234". If the third argument is not
2629 * specified, it returns the substring starting at the position specified
2630 * in the second argument and continuing to the end of the string. For
2631 * example, substring("12345",2) returns "2345". More precisely, each
2632 * character in the string (see [3.6 Strings]) is considered to have a
2633 * numeric position: the position of the first character is 1, the position
2634 * of the second character is 2 and so on. The returned substring contains
2635 * those characters for which the position of the character is greater than
2636 * or equal to the second argument and, if the third argument is specified,
2637 * less than the sum of the second and third arguments; the comparisons
2638 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2639 * - substring("12345", 1.5, 2.6) returns "234"
2640 * - substring("12345", 0, 3) returns "12"
2641 * - substring("12345", 0 div 0, 3) returns ""
2642 * - substring("12345", 1, 0 div 0) returns ""
2643 * - substring("12345", -42, 1 div 0) returns "12345"
2644 * - substring("12345", -1 div 0, 1 div 0) returns ""
2645 */
2646void
2647xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2648 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002649 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002650 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002651 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002652
2653 /*
2654 * Conformance needs to be checked !!!!!
2655 */
2656 if (nargs < 2) {
2657 CHECK_ARITY(2);
2658 }
2659 if (nargs > 3) {
2660 CHECK_ARITY(3);
2661 }
2662 if (nargs == 3) {
2663 CHECK_TYPE(XPATH_NUMBER);
2664 len = valuePop(ctxt);
2665 le = len->floatval;
2666 xmlXPathFreeObject(len);
2667 } else {
2668 le = 2000000000;
2669 }
2670 CHECK_TYPE(XPATH_NUMBER);
2671 start = valuePop(ctxt);
2672 in = start->floatval;
2673 xmlXPathFreeObject(start);
2674 CHECK_TYPE(XPATH_STRING);
2675 str = valuePop(ctxt);
2676 le += in;
2677
2678 /* integer index of the first char */
2679 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002680 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002681
2682 /* integer index of the last char */
2683 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002684 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002685
2686 /* back to a zero based len */
2687 i--;
2688 l--;
2689
2690 /* check against the string len */
2691 if (l > 1024) {
2692 l = xmlStrlen(str->stringval);
2693 }
2694 if (i < 0) {
2695 i = 0;
2696 }
2697
2698 /* number of chars to copy */
2699 l -= i;
2700
2701 ret = xmlStrsub(str->stringval, i, l);
2702 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002703 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002704 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002705 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002706 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002707 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002708 xmlXPathFreeObject(str);
2709}
2710
2711/**
2712 * xmlXPathSubstringBeforeFunction:
2713 * @ctxt: the XPath Parser context
2714 *
2715 * Implement the substring-before() XPath function
2716 * The substring-before function returns the substring of the first
2717 * argument string that precedes the first occurrence of the second
2718 * argument string in the first argument string, or the empty string
2719 * if the first argument string does not contain the second argument
2720 * string. For example, substring-before("1999/04/01","/") returns 1999.
2721 */
2722void
2723xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2724 CHECK_ARITY(2);
2725 TODO /* substring before */
2726}
2727
2728/**
2729 * xmlXPathSubstringAfterFunction:
2730 * @ctxt: the XPath Parser context
2731 *
2732 * Implement the substring-after() XPath function
2733 * The substring-after function returns the substring of the first
2734 * argument string that follows the first occurrence of the second
2735 * argument string in the first argument string, or the empty stringi
2736 * if the first argument string does not contain the second argument
2737 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2738 * and substring-after("1999/04/01","19") returns 99/04/01.
2739 */
2740void
2741xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2742 CHECK_ARITY(2);
2743 TODO /* substring after */
2744}
2745
2746/**
2747 * xmlXPathNormalizeFunction:
2748 * @ctxt: the XPath Parser context
2749 *
2750 * Implement the normalize() XPath function
2751 * The normalize function returns the argument string with white
2752 * space normalized by stripping leading and trailing whitespace
2753 * and replacing sequences of whitespace characters by a single
2754 * space. Whitespace characters are the same allowed by the S production
2755 * in XML. If the argument is omitted, it defaults to the context
2756 * node converted to a string, in other words the value of the context node.
2757 */
2758void
2759xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2760 CHECK_ARITY(1);
2761 TODO /* normalize isn't as boring as translate, but pretty much */
2762}
2763
2764/**
2765 * xmlXPathTranslateFunction:
2766 * @ctxt: the XPath Parser context
2767 *
2768 * Implement the translate() XPath function
2769 * The translate function returns the first argument string with
2770 * occurrences of characters in the second argument string replaced
2771 * by the character at the corresponding position in the third argument
2772 * string. For example, translate("bar","abc","ABC") returns the string
2773 * BAr. If there is a character in the second argument string with no
2774 * character at a corresponding position in the third argument string
2775 * (because the second argument string is longer than the third argument
2776 * string), then occurrences of that character in the first argument
2777 * string are removed. For example, translate("--aaa--","abc-","ABC")
2778 * returns "AAA". If a character occurs more than once in second
2779 * argument string, then the first occurrence determines the replacement
2780 * character. If the third argument string is longer than the second
2781 * argument string, then excess characters are ignored.
2782 */
2783void
2784xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2785 CHECK_ARITY(3);
2786 TODO /* translate is boring, waiting for UTF-8 representation too */
2787}
2788
2789/**
2790 * xmlXPathBooleanFunction:
2791 * @ctxt: the XPath Parser context
2792 *
2793 * Implement the boolean() XPath function
2794 * he boolean function converts its argument to a boolean as follows:
2795 * - a number is true if and only if it is neither positive or
2796 * negative zero nor NaN
2797 * - a node-set is true if and only if it is non-empty
2798 * - a string is true if and only if its length is non-zero
2799 */
2800void
2801xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2802 xmlXPathObjectPtr cur;
2803 int res = 0;
2804
2805 CHECK_ARITY(1);
2806 cur = valuePop(ctxt);
2807 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2808 switch (cur->type) {
2809 case XPATH_NODESET:
2810 if ((cur->nodesetval == NULL) ||
2811 (cur->nodesetval->nodeNr == 0)) res = 0;
2812 else
2813 res = 1;
2814 break;
2815 case XPATH_STRING:
2816 if ((cur->stringval == NULL) ||
2817 (cur->stringval[0] == 0)) res = 0;
2818 else
2819 res = 1;
2820 break;
2821 case XPATH_BOOLEAN:
2822 valuePush(ctxt, cur);
2823 return;
2824 case XPATH_NUMBER:
2825 if (cur->floatval) res = 1;
2826 break;
2827 default:
2828 STRANGE
2829 }
2830 xmlXPathFreeObject(cur);
2831 valuePush(ctxt, xmlXPathNewBoolean(res));
2832}
2833
2834/**
2835 * xmlXPathNotFunction:
2836 * @ctxt: the XPath Parser context
2837 *
2838 * Implement the not() XPath function
2839 * The not function returns true if its argument is false,
2840 * and false otherwise.
2841 */
2842void
2843xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2844 CHECK_ARITY(1);
2845 CHECK_TYPE(XPATH_BOOLEAN);
2846 ctxt->value->boolval = ! ctxt->value->boolval;
2847}
2848
2849/**
2850 * xmlXPathTrueFunction:
2851 * @ctxt: the XPath Parser context
2852 *
2853 * Implement the true() XPath function
2854 */
2855void
2856xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2857 CHECK_ARITY(0);
2858 valuePush(ctxt, xmlXPathNewBoolean(1));
2859}
2860
2861/**
2862 * xmlXPathFalseFunction:
2863 * @ctxt: the XPath Parser context
2864 *
2865 * Implement the false() XPath function
2866 */
2867void
2868xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2869 CHECK_ARITY(0);
2870 valuePush(ctxt, xmlXPathNewBoolean(0));
2871}
2872
2873/**
2874 * xmlXPathLangFunction:
2875 * @ctxt: the XPath Parser context
2876 *
2877 * Implement the lang() XPath function
2878 * The lang function returns true or false depending on whether the
2879 * language of the context node as specified by xml:lang attributes
2880 * is the same as or is a sublanguage of the language specified by
2881 * the argument string. The language of the context node is determined
2882 * by the value of the xml:lang attribute on the context node, or, if
2883 * the context node has no xml:lang attribute, by the value of the
2884 * xml:lang attribute on the nearest ancestor of the context node that
2885 * has an xml:lang attribute. If there is no such attribute, then lang
2886 * returns false. If there is such an attribute, then lang returns
2887 * true if the attribute value is equal to the argument ignoring case,
2888 * or if there is some suffix starting with - such that the attribute
2889 * value is equal to the argument ignoring that suffix of the attribute
2890 * value and ignoring case.
2891 */
2892void
2893xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002894 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002895 const xmlChar *theLang;
2896 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002897 int ret = 0;
2898 int i;
2899
2900 CHECK_ARITY(1);
2901 CHECK_TYPE(XPATH_STRING);
2902 val = valuePop(ctxt);
2903 lang = val->stringval;
2904 theLang = xmlNodeGetLang(ctxt->context->node);
2905 if ((theLang != NULL) && (lang != NULL)) {
2906 for (i = 0;lang[i] != 0;i++)
2907 if (toupper(lang[i]) != toupper(theLang[i]))
2908 goto not_equal;
2909 ret = 1;
2910 }
2911not_equal:
2912 xmlXPathFreeObject(val);
2913 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002914}
2915
2916/**
2917 * xmlXPathNumberFunction:
2918 * @ctxt: the XPath Parser context
2919 *
2920 * Implement the number() XPath function
2921 */
2922void
2923xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2924 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002925 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002926
2927 CHECK_ARITY(1);
2928 cur = valuePop(ctxt);
2929 switch (cur->type) {
2930 case XPATH_NODESET:
2931 valuePush(ctxt, cur);
2932 xmlXPathStringFunction(ctxt, 1);
2933 cur = valuePop(ctxt);
2934 case XPATH_STRING:
2935 res = xmlXPathStringEvalNumber(cur->stringval);
2936 valuePush(ctxt, xmlXPathNewFloat(res));
2937 xmlXPathFreeObject(cur);
2938 return;
2939 case XPATH_BOOLEAN:
2940 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2941 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2942 xmlXPathFreeObject(cur);
2943 return;
2944 case XPATH_NUMBER:
2945 valuePush(ctxt, cur);
2946 return;
2947 }
2948 STRANGE
2949}
2950
2951/**
2952 * xmlXPathSumFunction:
2953 * @ctxt: the XPath Parser context
2954 *
2955 * Implement the sum() XPath function
2956 * The sum function returns the sum of the values of the nodes in
2957 * the argument node-set.
2958 */
2959void
2960xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2961 CHECK_ARITY(1);
2962 TODO /* BUG Sum : don't understand the definition */
2963}
2964
2965/**
2966 * xmlXPathFloorFunction:
2967 * @ctxt: the XPath Parser context
2968 *
2969 * Implement the floor() XPath function
2970 * The floor function returns the largest (closest to positive infinity)
2971 * number that is not greater than the argument and that is an integer.
2972 */
2973void
2974xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2975 CHECK_ARITY(1);
2976 CHECK_TYPE(XPATH_NUMBER);
2977 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002978 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002979}
2980
2981/**
2982 * xmlXPathCeilingFunction:
2983 * @ctxt: the XPath Parser context
2984 *
2985 * Implement the ceiling() XPath function
2986 * The ceiling function returns the smallest (closest to negative infinity)
2987 * number that is not less than the argument and that is an integer.
2988 */
2989void
2990xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002991 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002992
2993 CHECK_ARITY(1);
2994 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002995 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002996 if (f != ctxt->value->floatval)
2997 ctxt->value->floatval = f + 1;
2998}
2999
3000/**
3001 * xmlXPathRoundFunction:
3002 * @ctxt: the XPath Parser context
3003 *
3004 * Implement the round() XPath function
3005 * The round function returns the number that is closest to the
3006 * argument and that is an integer. If there are two such numbers,
3007 * then the one that is even is returned.
3008 */
3009void
3010xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003011 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003012
3013 CHECK_ARITY(1);
3014 CHECK_TYPE(XPATH_NUMBER);
3015 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003016 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003017 if (ctxt->value->floatval < f + 0.5)
3018 ctxt->value->floatval = f;
3019 else if (ctxt->value->floatval == f + 0.5)
3020 ctxt->value->floatval = f; /* !!!! Not following the spec here */
3021 else
3022 ctxt->value->floatval = f + 1;
3023}
3024
3025/************************************************************************
3026 * *
3027 * The Parser *
3028 * *
3029 ************************************************************************/
3030
3031/*
3032 * a couple of forward declarations since we use a recursive call based
3033 * implementation.
3034 */
3035void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3036void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3037void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3038void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3039
3040/**
3041 * xmlXPathParseNCName:
3042 * @ctxt: the XPath Parser context
3043 *
3044 * parse an XML namespace non qualified name.
3045 *
3046 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3047 *
3048 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3049 * CombiningChar | Extender
3050 *
3051 * Returns the namespace name or NULL
3052 */
3053
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003054xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003055xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003056 const xmlChar *q;
3057 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003058
3059 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3060 q = NEXT;
3061
3062 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3063 (CUR == '.') || (CUR == '-') ||
3064 (CUR == '_') ||
3065 (IS_COMBINING(CUR)) ||
3066 (IS_EXTENDER(CUR)))
3067 NEXT;
3068
3069 ret = xmlStrndup(q, CUR_PTR - q);
3070
3071 return(ret);
3072}
3073
3074/**
3075 * xmlXPathParseQName:
3076 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003077 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003078 *
3079 * parse an XML qualified name
3080 *
3081 * [NS 5] QName ::= (Prefix ':')? LocalPart
3082 *
3083 * [NS 6] Prefix ::= NCName
3084 *
3085 * [NS 7] LocalPart ::= NCName
3086 *
3087 * Returns the function returns the local part, and prefix is updated
3088 * to get the Prefix if any.
3089 */
3090
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003091xmlChar *
3092xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3093 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003094
3095 *prefix = NULL;
3096 ret = xmlXPathParseNCName(ctxt);
3097 if (CUR == ':') {
3098 *prefix = ret;
3099 NEXT;
3100 ret = xmlXPathParseNCName(ctxt);
3101 }
3102 return(ret);
3103}
3104
3105/**
3106 * xmlXPathStringEvalNumber:
3107 * @str: A string to scan
3108 *
3109 * [30] Number ::= Digits ('.' Digits)?
3110 * | '.' Digits
3111 * [31] Digits ::= [0-9]+
3112 *
3113 * Parse and evaluate a Number in the string
3114 *
3115 * BUG: "1.' is not valid ... James promised correction
3116 * as Digits ('.' Digits?)?
3117 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003118 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003119 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003120double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003121xmlXPathStringEvalNumber(const xmlChar *str) {
3122 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003123 double ret = 0.0;
3124 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003125 int ok = 0;
3126
3127 while (*cur == ' ') cur++;
3128 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003129 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003130 }
3131 while ((*cur >= '0') && (*cur <= '9')) {
3132 ret = ret * 10 + (*cur - '0');
3133 ok = 1;
3134 cur++;
3135 }
3136 if (*cur == '.') {
3137 cur++;
3138 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003139 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003140 }
3141 while ((*cur >= '0') && (*cur <= '9')) {
3142 mult /= 10;
3143 ret = ret + (*cur - '0') * mult;
3144 cur++;
3145 }
3146 }
3147 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003148 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003149 return(ret);
3150}
3151
3152/**
3153 * xmlXPathEvalNumber:
3154 * @ctxt: the XPath Parser context
3155 *
3156 * [30] Number ::= Digits ('.' Digits)?
3157 * | '.' Digits
3158 * [31] Digits ::= [0-9]+
3159 *
3160 * Parse and evaluate a Number, then push it on the stack
3161 *
3162 * BUG: "1.' is not valid ... James promised correction
3163 * as Digits ('.' Digits?)?
3164 */
3165void
3166xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003167 double ret = 0.0;
3168 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003169 int ok = 0;
3170
3171 CHECK_ERROR;
3172 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3173 ERROR(XPATH_NUMBER_ERROR);
3174 }
3175 while ((CUR >= '0') && (CUR <= '9')) {
3176 ret = ret * 10 + (CUR - '0');
3177 ok = 1;
3178 NEXT;
3179 }
3180 if (CUR == '.') {
3181 NEXT;
3182 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3183 ERROR(XPATH_NUMBER_ERROR);
3184 }
3185 while ((CUR >= '0') && (CUR <= '9')) {
3186 mult /= 10;
3187 ret = ret + (CUR - '0') * mult;
3188 NEXT;
3189 }
3190 }
3191 valuePush(ctxt, xmlXPathNewFloat(ret));
3192}
3193
3194/**
3195 * xmlXPathEvalLiteral:
3196 * @ctxt: the XPath Parser context
3197 *
3198 * Parse a Literal and push it on the stack.
3199 *
3200 * [29] Literal ::= '"' [^"]* '"'
3201 * | "'" [^']* "'"
3202 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003203 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003204 */
3205void
3206xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003207 const xmlChar *q;
3208 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003209
3210 if (CUR == '"') {
3211 NEXT;
3212 q = CUR_PTR;
3213 while ((IS_CHAR(CUR)) && (CUR != '"'))
3214 NEXT;
3215 if (!IS_CHAR(CUR)) {
3216 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3217 } else {
3218 ret = xmlStrndup(q, CUR_PTR - q);
3219 NEXT;
3220 }
3221 } else if (CUR == '\'') {
3222 NEXT;
3223 q = CUR_PTR;
3224 while ((IS_CHAR(CUR)) && (CUR != '\''))
3225 NEXT;
3226 if (!IS_CHAR(CUR)) {
3227 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3228 } else {
3229 ret = xmlStrndup(q, CUR_PTR - q);
3230 NEXT;
3231 }
3232 } else {
3233 ERROR(XPATH_START_LITERAL_ERROR);
3234 }
3235 if (ret == NULL) return;
3236 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003237 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003238}
3239
3240/**
3241 * xmlXPathEvalVariableReference:
3242 * @ctxt: the XPath Parser context
3243 *
3244 * Parse a VariableReference, evaluate it and push it on the stack.
3245 *
3246 * The variable bindings consist of a mapping from variable names
3247 * to variable values. The value of a variable is an object, which
3248 * of any of the types that are possible for the value of an expression,
3249 * and may also be of additional types not specified here.
3250 *
3251 * Early evaluation is possible since:
3252 * The variable bindings [...] used to evaluate a subexpression are
3253 * always the same as those used to evaluate the containing expression.
3254 *
3255 * [36] VariableReference ::= '$' QName
3256 */
3257void
3258xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003259 xmlChar *name;
3260 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003261 xmlXPathObjectPtr value;
3262
3263 if (CUR != '$') {
3264 ERROR(XPATH_VARIABLE_REF_ERROR);
3265 }
3266 name = xmlXPathParseQName(ctxt, &prefix);
3267 if (name == NULL) {
3268 ERROR(XPATH_VARIABLE_REF_ERROR);
3269 }
3270 value = xmlXPathVariablelookup(ctxt, prefix, name);
3271 if (value == NULL) {
3272 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3273 }
3274 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003275 if (prefix != NULL) xmlFree(prefix);
3276 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003277}
3278
3279
3280/**
3281 * xmlXPathFunctionLookup:
3282 * @ctxt: the XPath Parser context
3283 * @name: a name string
3284 *
3285 * Search for a function of the given name
3286 *
3287 * [35] FunctionName ::= QName - NodeType
3288 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003289 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003290 *
3291 * Returns the xmlXPathFunction if found, or NULL otherwise
3292 */
3293xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003294xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003295 switch (name[0]) {
3296 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003297 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003298 return(xmlXPathBooleanFunction);
3299 break;
3300 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003301 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003302 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003303 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003304 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003305 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003306 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003307 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003308 return(xmlXPathContainsFunction);
3309 break;
3310 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003311 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003312 return(xmlXPathIdFunction);
3313 break;
3314 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003315 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003316 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003317 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003318 return(xmlXPathFloorFunction);
3319 break;
3320 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003321 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003322 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003323 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003324 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003325 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003326 return(xmlXPathLocalPartFunction);
3327 break;
3328 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003329 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003330 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003331 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003332 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003333 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003334 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003335 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3336 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003337 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003338 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003339 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003340 return(xmlXPathNumberFunction);
3341 break;
3342 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003343 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003344 return(xmlXPathPositionFunction);
3345 break;
3346 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003347 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003348 return(xmlXPathRoundFunction);
3349 break;
3350 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003351 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003352 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003353 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003354 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003355 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003356 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003357 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003358 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003359 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003360 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003361 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003362 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003363 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003364 return(xmlXPathSumFunction);
3365 break;
3366 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003367 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003368 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003369 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003370 return(xmlXPathTranslateFunction);
3371 break;
3372 }
3373 return(NULL);
3374}
3375
3376/**
3377 * xmlXPathEvalLocationPathName:
3378 * @ctxt: the XPath Parser context
3379 * @name: a name string
3380 *
3381 * Various names in the beginning of a LocationPath expression
3382 * indicate whether that's an Axis, a node type,
3383 *
3384 * [6] AxisName ::= 'ancestor'
3385 * | 'ancestor-or-self'
3386 * | 'attribute'
3387 * | 'child'
3388 * | 'descendant'
3389 * | 'descendant-or-self'
3390 * | 'following'
3391 * | 'following-sibling'
3392 * | 'namespace'
3393 * | 'parent'
3394 * | 'preceding'
3395 * | 'preceding-sibling'
3396 * | 'self'
3397 * [38] NodeType ::= 'comment'
3398 * | 'text'
3399 * | 'processing-instruction'
3400 * | 'node'
3401 */
3402int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003403xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003404 switch (name[0]) {
3405 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003406 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3407 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3408 return(AXIS_ANCESTOR_OR_SELF);
3409 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003410 break;
3411 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003412 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3413 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003414 break;
3415 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003416 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3417 return(AXIS_DESCENDANT);
3418 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3419 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003420 break;
3421 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003422 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3423 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3424 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003425 break;
3426 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003427 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3428 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003429 break;
3430 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003431 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3432 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3433 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3434 return(AXIS_PRECEDING_SIBLING);
3435 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3436 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003437 break;
3438 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003439 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003440 break;
3441 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003442 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003443 break;
3444 }
3445 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3446 return(0);
3447}
3448
3449/**
3450 * xmlXPathEvalFunctionCall:
3451 * @ctxt: the XPath Parser context
3452 *
3453 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3454 * [17] Argument ::= Expr
3455 *
3456 * Parse and evaluate a function call, the evaluation of all arguments are
3457 * pushed on the stack
3458 */
3459void
3460xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003461 xmlChar *name;
3462 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003463 xmlXPathFunction func;
3464 int nbargs = 0;
3465
3466 name = xmlXPathParseQName(ctxt, &prefix);
3467 if (name == NULL) {
3468 ERROR(XPATH_EXPR_ERROR);
3469 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003470 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003471 func = xmlXPathIsFunction(ctxt, name);
3472 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003473 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003474 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3475 }
3476#ifdef DEBUG_EXPR
3477 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3478#endif
3479
3480 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003481 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003482 ERROR(XPATH_EXPR_ERROR);
3483 }
3484 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003485 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003486
3487 while (CUR != ')') {
3488 xmlXPathEvalExpr(ctxt);
3489 nbargs++;
3490 if (CUR == ')') break;
3491 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003492 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003493 ERROR(XPATH_EXPR_ERROR);
3494 }
3495 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003496 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003497 }
3498 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003499 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003500 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003501 func(ctxt, nbargs);
3502}
3503
3504/**
3505 * xmlXPathEvalPrimaryExpr:
3506 * @ctxt: the XPath Parser context
3507 *
3508 * [15] PrimaryExpr ::= VariableReference
3509 * | '(' Expr ')'
3510 * | Literal
3511 * | Number
3512 * | FunctionCall
3513 *
3514 * Parse and evaluate a primary expression, then push the result on the stack
3515 */
3516void
3517xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003518 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003519 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3520 else if (CUR == '(') {
3521 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003522 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003523 xmlXPathEvalExpr(ctxt);
3524 if (CUR != ')') {
3525 ERROR(XPATH_EXPR_ERROR);
3526 }
3527 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003528 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003529 } else if (IS_DIGIT(CUR)) {
3530 xmlXPathEvalNumber(ctxt);
3531 } else if ((CUR == '\'') || (CUR == '"')) {
3532 xmlXPathEvalLiteral(ctxt);
3533 } else {
3534 xmlXPathEvalFunctionCall(ctxt);
3535 }
3536}
3537
3538/**
3539 * xmlXPathEvalFilterExpr:
3540 * @ctxt: the XPath Parser context
3541 *
3542 * [20] FilterExpr ::= PrimaryExpr
3543 * | FilterExpr Predicate
3544 *
3545 * Parse and evaluate a filter expression, then push the result on the stack
3546 * Square brackets are used to filter expressions in the same way that
3547 * they are used in location paths. It is an error if the expression to
3548 * be filtered does not evaluate to a node-set. The context node list
3549 * used for evaluating the expression in square brackets is the node-set
3550 * to be filtered listed in document order.
3551 */
3552
3553void
3554xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3555 /****
3556 xmlNodeSetPtr oldset = NULL;
3557 xmlXPathObjectPtr arg;
3558 ****/
3559
3560 xmlXPathEvalPrimaryExpr(ctxt);
3561 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003562 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003563
3564 if (CUR != '[') return;
3565
3566 CHECK_TYPE(XPATH_NODESET);
3567
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003568 while (CUR == '[') {
3569 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003570 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003571 }
3572
3573
3574}
3575
3576/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003577 * xmlXPathScanName:
3578 * @ctxt: the XPath Parser context
3579 *
3580 * Trickery: parse an XML name but without consuming the input flow
3581 * Needed for rollback cases.
3582 *
3583 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3584 * CombiningChar | Extender
3585 *
3586 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3587 *
3588 * [6] Names ::= Name (S Name)*
3589 *
3590 * Returns the Name parsed or NULL
3591 */
3592
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003593xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003594xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003595 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003596 int len = 0;
3597
Daniel Veillard00fdf371999-10-08 09:40:39 +00003598 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003599 if (!IS_LETTER(CUR) && (CUR != '_') &&
3600 (CUR != ':')) {
3601 return(NULL);
3602 }
3603
3604 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3605 (NXT(len) == '.') || (NXT(len) == '-') ||
3606 (NXT(len) == '_') || (NXT(len) == ':') ||
3607 (IS_COMBINING(NXT(len))) ||
3608 (IS_EXTENDER(NXT(len)))) {
3609 buf[len] = NXT(len);
3610 len++;
3611 if (len >= XML_MAX_NAMELEN) {
3612 fprintf(stderr,
3613 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3614 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3615 (NXT(len) == '.') || (NXT(len) == '-') ||
3616 (NXT(len) == '_') || (NXT(len) == ':') ||
3617 (IS_COMBINING(NXT(len))) ||
3618 (IS_EXTENDER(NXT(len))))
3619 len++;
3620 break;
3621 }
3622 }
3623 return(xmlStrndup(buf, len));
3624}
3625
3626/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003627 * xmlXPathEvalPathExpr:
3628 * @ctxt: the XPath Parser context
3629 *
3630 * [19] PathExpr ::= LocationPath
3631 * | FilterExpr
3632 * | FilterExpr '/' RelativeLocationPath
3633 * | FilterExpr '//' RelativeLocationPath
3634 *
3635 * Parse and evaluate a path expression, then push the result on the stack
3636 * The / operator and // operators combine an arbitrary expression
3637 * and a relative location path. It is an error if the expression
3638 * does not evaluate to a node-set.
3639 * The / operator does composition in the same way as when / is
3640 * used in a location path. As in location paths, // is short for
3641 * /descendant-or-self::node()/.
3642 */
3643
3644void
3645xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3646 xmlNodeSetPtr newset = NULL;
3647
Daniel Veillard00fdf371999-10-08 09:40:39 +00003648 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003649 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3650 (CUR == '\'') || (CUR == '"')) {
3651 xmlXPathEvalFilterExpr(ctxt);
3652 CHECK_ERROR;
3653 if ((CUR == '/') && (NXT(1) == '/')) {
3654 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003655 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003656 if (ctxt->context->nodelist == NULL) {
3657 STRANGE
3658 xmlXPathRoot(ctxt);
3659 }
3660 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3661 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3662 if (ctxt->context->nodelist != NULL)
3663 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3664 ctxt->context->nodelist = newset;
3665 ctxt->context->node = NULL;
3666 xmlXPathEvalRelativeLocationPath(ctxt);
3667 } else if (CUR == '/') {
3668 xmlXPathEvalRelativeLocationPath(ctxt);
3669 }
3670 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003671 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003672 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003673
3674 name = xmlXPathScanName(ctxt);
3675 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3676 xmlXPathEvalLocationPath(ctxt);
3677 else
3678 xmlXPathEvalFilterExpr(ctxt);
3679 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003680 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003681 }
3682}
3683
3684/**
3685 * xmlXPathEvalUnionExpr:
3686 * @ctxt: the XPath Parser context
3687 *
3688 * [18] UnionExpr ::= PathExpr
3689 * | UnionExpr '|' PathExpr
3690 *
3691 * Parse and evaluate an union expression, then push the result on the stack
3692 */
3693
3694void
3695xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3696 xmlXPathEvalPathExpr(ctxt);
3697 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003698 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003699 if (CUR == '|') {
3700 xmlNodeSetPtr old = ctxt->context->nodelist;
3701
Daniel Veillard00fdf371999-10-08 09:40:39 +00003702 NEXT;
3703 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003704 xmlXPathEvalPathExpr(ctxt);
3705
3706 if (ctxt->context->nodelist == NULL)
3707 ctxt->context->nodelist = old;
3708 else {
3709 ctxt->context->nodelist =
3710 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3711 xmlXPathFreeNodeSet(old);
3712 }
3713 }
3714}
3715
3716/**
3717 * xmlXPathEvalUnaryExpr:
3718 * @ctxt: the XPath Parser context
3719 *
3720 * [27] UnaryExpr ::= UnionExpr
3721 * | '-' UnaryExpr
3722 *
3723 * Parse and evaluate an unary expression, then push the result on the stack
3724 */
3725
3726void
3727xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3728 int minus = 0;
3729
Daniel Veillard00fdf371999-10-08 09:40:39 +00003730 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003731 if (CUR == '-') {
3732 minus = 1;
3733 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003734 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003735 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003736 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003737 CHECK_ERROR;
3738 if (minus) {
3739 xmlXPathValueFlipSign(ctxt);
3740 }
3741}
3742
3743/**
3744 * xmlXPathEvalMultiplicativeExpr:
3745 * @ctxt: the XPath Parser context
3746 *
3747 * [26] MultiplicativeExpr ::= UnaryExpr
3748 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3749 * | MultiplicativeExpr 'div' UnaryExpr
3750 * | MultiplicativeExpr 'mod' UnaryExpr
3751 * [34] MultiplyOperator ::= '*'
3752 *
3753 * Parse and evaluate an Additive expression, then push the result on the stack
3754 */
3755
3756void
3757xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3758 xmlXPathEvalUnaryExpr(ctxt);
3759 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003760 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003761 while ((CUR == '*') ||
3762 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3763 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3764 int op = -1;
3765
3766 if (CUR == '*') {
3767 op = 0;
3768 NEXT;
3769 } else if (CUR == 'd') {
3770 op = 1;
3771 SKIP(3);
3772 } else if (CUR == 'm') {
3773 op = 2;
3774 SKIP(3);
3775 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003776 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003777 xmlXPathEvalUnaryExpr(ctxt);
3778 CHECK_ERROR;
3779 switch (op) {
3780 case 0:
3781 xmlXPathMultValues(ctxt);
3782 break;
3783 case 1:
3784 xmlXPathDivValues(ctxt);
3785 break;
3786 case 2:
3787 xmlXPathModValues(ctxt);
3788 break;
3789 }
3790 }
3791}
3792
3793/**
3794 * xmlXPathEvalAdditiveExpr:
3795 * @ctxt: the XPath Parser context
3796 *
3797 * [25] AdditiveExpr ::= MultiplicativeExpr
3798 * | AdditiveExpr '+' MultiplicativeExpr
3799 * | AdditiveExpr '-' MultiplicativeExpr
3800 *
3801 * Parse and evaluate an Additive expression, then push the result on the stack
3802 */
3803
3804void
3805xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3806 xmlXPathEvalMultiplicativeExpr(ctxt);
3807 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003808 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003809 while ((CUR == '+') || (CUR == '-')) {
3810 int plus;
3811
3812 if (CUR == '+') plus = 1;
3813 else plus = 0;
3814 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003815 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003816 xmlXPathEvalMultiplicativeExpr(ctxt);
3817 CHECK_ERROR;
3818 if (plus) xmlXPathAddValues(ctxt);
3819 else xmlXPathSubValues(ctxt);
3820 }
3821}
3822
3823/**
3824 * xmlXPathEvalRelationalExpr:
3825 * @ctxt: the XPath Parser context
3826 *
3827 * [24] RelationalExpr ::= AdditiveExpr
3828 * | RelationalExpr '<' AdditiveExpr
3829 * | RelationalExpr '>' AdditiveExpr
3830 * | RelationalExpr '<=' AdditiveExpr
3831 * | RelationalExpr '>=' AdditiveExpr
3832 *
3833 * A <= B > C is allowed ? Answer from James, yes with
3834 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3835 * which is basically what got implemented.
3836 *
3837 * Parse and evaluate a Relational expression, then push the result
3838 * on the stack
3839 */
3840
3841void
3842xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3843 xmlXPathEvalAdditiveExpr(ctxt);
3844 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003845 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003846 while ((CUR == '<') ||
3847 (CUR == '>') ||
3848 ((CUR == '<') && (NXT(1) == '=')) ||
3849 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003850 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003851
3852 if (CUR == '<') inf = 1;
3853 else inf = 0;
3854 if (NXT(1) == '=') strict = 0;
3855 else strict = 1;
3856 NEXT;
3857 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003858 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003859 xmlXPathEvalAdditiveExpr(ctxt);
3860 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003861 ret = xmlXPathCompareValues(ctxt, inf, strict);
3862 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003863 }
3864}
3865
3866/**
3867 * xmlXPathEvalEqualityExpr:
3868 * @ctxt: the XPath Parser context
3869 *
3870 * [23] EqualityExpr ::= RelationalExpr
3871 * | EqualityExpr '=' RelationalExpr
3872 * | EqualityExpr '!=' RelationalExpr
3873 *
3874 * A != B != C is allowed ? Answer from James, yes with
3875 * (RelationalExpr = RelationalExpr) = RelationalExpr
3876 * (RelationalExpr != RelationalExpr) != RelationalExpr
3877 * which is basically what got implemented.
3878 *
3879 * Parse and evaluate an Equality expression, then push the result on the stack
3880 *
3881 */
3882void
3883xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3884 xmlXPathEvalRelationalExpr(ctxt);
3885 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003886 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003887 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003888 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003889 int eq, equal;
3890
3891 if (CUR == '=') eq = 1;
3892 else eq = 0;
3893 NEXT;
3894 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003895 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003896 xmlXPathEvalRelationalExpr(ctxt);
3897 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003898 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003899 if (eq) res = xmlXPathNewBoolean(equal);
3900 else res = xmlXPathNewBoolean(!equal);
3901 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003902 }
3903}
3904
3905/**
3906 * xmlXPathEvalAndExpr:
3907 * @ctxt: the XPath Parser context
3908 *
3909 * [22] AndExpr ::= EqualityExpr
3910 * | AndExpr 'and' EqualityExpr
3911 *
3912 * Parse and evaluate an AND expression, then push the result on the stack
3913 *
3914 */
3915void
3916xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3917 xmlXPathEvalEqualityExpr(ctxt);
3918 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003919 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003920 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3921 xmlXPathObjectPtr arg1, arg2;
3922
3923 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003924 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003925 xmlXPathEvalEqualityExpr(ctxt);
3926 CHECK_ERROR;
3927 arg2 = valuePop(ctxt);
3928 arg1 = valuePop(ctxt);
3929 arg1->boolval &= arg2->boolval;
3930 valuePush(ctxt, arg1);
3931 xmlXPathFreeObject(arg2);
3932 }
3933}
3934
3935/**
3936 * xmlXPathEvalExpr:
3937 * @ctxt: the XPath Parser context
3938 *
3939 * [14] Expr ::= OrExpr
3940 * [21] OrExpr ::= AndExpr
3941 * | OrExpr 'or' AndExpr
3942 *
3943 * Parse and evaluate an expression, then push the result on the stack
3944 *
3945 */
3946void
3947xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3948 xmlXPathEvalAndExpr(ctxt);
3949 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003950 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003951 while ((CUR == 'o') && (NXT(1) == 'r')) {
3952 xmlXPathObjectPtr arg1, arg2;
3953
3954 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003955 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003956 xmlXPathEvalAndExpr(ctxt);
3957 CHECK_ERROR;
3958 arg2 = valuePop(ctxt);
3959 arg1 = valuePop(ctxt);
3960 arg1->boolval |= arg2->boolval;
3961 valuePush(ctxt, arg1);
3962 xmlXPathFreeObject(arg2);
3963 }
3964}
3965
3966/**
3967 * xmlXPathEvaluatePredicateResult:
3968 * @ctxt: the XPath Parser context
3969 * @res: the Predicate Expression evaluation result
3970 * @index: index of the current node in the current list
3971 *
3972 * Evaluate a predicate result for the current node.
3973 * A PredicateExpr is evaluated by evaluating the Expr and converting
3974 * the result to a boolean. If the result is a number, the result will
3975 * be converted to true if the number is equal to the position of the
3976 * context node in the context node list (as returned by the position
3977 * function) and will be converted to false otherwise; if the result
3978 * is not a number, then the result will be converted as if by a call
3979 * to the boolean function.
3980 */
3981int
3982xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3983 xmlXPathObjectPtr res, int index) {
3984 if (res == NULL) return(0);
3985 switch (res->type) {
3986 case XPATH_BOOLEAN:
3987 return(res->boolval);
3988 case XPATH_NUMBER:
3989 return(res->floatval == index);
3990 case XPATH_NODESET:
3991 return(res->nodesetval->nodeNr != 0);
3992 case XPATH_STRING:
3993 return((res->stringval != NULL) &&
3994 (xmlStrlen(res->stringval) != 0));
3995 default:
3996 STRANGE
3997 }
3998 return(0);
3999}
4000
4001/**
4002 * xmlXPathEvalPredicate:
4003 * @ctxt: the XPath Parser context
4004 *
4005 * [8] Predicate ::= '[' PredicateExpr ']'
4006 * [9] PredicateExpr ::= Expr
4007 *
4008 * Parse and evaluate a predicate for all the elements of the
4009 * current node list. Then refine the list by removing all
4010 * nodes where the predicate is false.
4011 */
4012void
4013xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004014 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004015 xmlXPathObjectPtr res;
4016 xmlNodeSetPtr newset = NULL;
4017 int i;
4018
Daniel Veillard00fdf371999-10-08 09:40:39 +00004019 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004020 if (CUR != '[') {
4021 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4022 }
4023 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004024 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004025 if ((ctxt->context->nodelist == NULL) ||
4026 (ctxt->context->nodelist->nodeNr == 0)) {
4027 ctxt->context->node = NULL;
4028 xmlXPathEvalExpr(ctxt);
4029 CHECK_ERROR;
4030 res = valuePop(ctxt);
4031 if (res != NULL)
4032 xmlXPathFreeObject(res);
4033 } else {
4034 cur = ctxt->cur;
4035 newset = xmlXPathNodeSetCreate(NULL);
4036 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
4037 ctxt->cur = cur;
4038 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
4039 xmlXPathEvalExpr(ctxt);
4040 CHECK_ERROR;
4041 res = valuePop(ctxt);
4042 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
4043 xmlXPathNodeSetAdd(newset,
4044 ctxt->context->nodelist->nodeTab[i]);
4045 if (res != NULL)
4046 xmlXPathFreeObject(res);
4047 }
4048 if (ctxt->context->nodelist != NULL)
4049 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4050 ctxt->context->nodelist = newset;
4051 ctxt->context->node = NULL;
4052 }
4053 if (CUR != ']') {
4054 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4055 }
4056 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004057 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004058#ifdef DEBUG_STEP
4059 fprintf(xmlXPathDebug, "After predicate : ");
4060 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4061#endif
4062}
4063
4064/**
4065 * xmlXPathEvalBasis:
4066 * @ctxt: the XPath Parser context
4067 *
4068 * [5] Basis ::= AxisName '::' NodeTest
4069 * | AbbreviatedBasis
4070 * [13] AbbreviatedBasis ::= NodeTest
4071 * | '@' NodeTest
4072 * [7] NodeTest ::= WildcardName
4073 * | NodeType '(' ')'
4074 * | 'processing-instruction' '(' Literal ')'
4075 * [37] WildcardName ::= '*'
4076 * | NCName ':' '*'
4077 * | QName
4078 *
4079 * Evaluate one step in a Location Path
4080 */
4081void
4082xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004083 xmlChar *name = NULL;
4084 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004085 int type = 0;
4086 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4087 int nodetest = NODE_TEST_NONE;
4088 int nodetype = 0;
4089 xmlNodeSetPtr newset = NULL;
4090
4091 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004092 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004093 axis = AXIS_ATTRIBUTE;
4094 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004095 } else if (CUR == '*') {
4096 NEXT;
4097 nodetest = NODE_TEST_ALL;
4098 } else {
4099 name = xmlXPathParseNCName(ctxt);
4100 if (name == NULL) {
4101 ERROR(XPATH_EXPR_ERROR);
4102 }
4103 type = xmlXPathGetNameType(ctxt, name);
4104 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004105 case IS_FUNCTION: {
4106 xmlXPathFunction func;
4107 int nbargs = 0;
4108 xmlXPathObjectPtr top;
4109
4110 top = ctxt->value;
4111 func = xmlXPathIsFunction(ctxt, name);
4112 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004113 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004114 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4115 }
4116#ifdef DEBUG_EXPR
4117 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4118#endif
4119
4120 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004121 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004122 ERROR(XPATH_EXPR_ERROR);
4123 }
4124 NEXT;
4125
4126 while (CUR != ')') {
4127 xmlXPathEvalExpr(ctxt);
4128 nbargs++;
4129 if (CUR == ')') break;
4130 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004131 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004132 ERROR(XPATH_EXPR_ERROR);
4133 }
4134 NEXT;
4135 }
4136 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004137 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004138 func(ctxt, nbargs);
4139 if ((ctxt->value != top) &&
4140 (ctxt->value != NULL) &&
4141 (ctxt->value->type == XPATH_NODESET)) {
4142 xmlXPathObjectPtr cur;
4143
4144 cur = valuePop(ctxt);
4145 ctxt->context->nodelist = cur->nodesetval;
4146 ctxt->context->node = NULL;
4147 cur->nodesetval = NULL;
4148 xmlXPathFreeObject(cur);
4149 }
4150 return;
4151 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004152 /*
4153 * Simple case: no axis seach all given node types.
4154 */
4155 case NODE_TYPE_COMMENT:
4156 if ((CUR != '(') || (NXT(1) != ')')) break;
4157 SKIP(2);
4158 nodetest = NODE_TEST_TYPE;
4159 nodetype = XML_COMMENT_NODE;
4160 goto search_nodes;
4161 case NODE_TYPE_TEXT:
4162 if ((CUR != '(') || (NXT(1) != ')')) break;
4163 SKIP(2);
4164 nodetest = NODE_TEST_TYPE;
4165 nodetype = XML_TEXT_NODE;
4166 goto search_nodes;
4167 case NODE_TYPE_NODE:
4168 if ((CUR != '(') || (NXT(1) != ')')) {
4169 nodetest = NODE_TEST_NAME;
4170 break;
4171 }
4172 SKIP(2);
4173 nodetest = NODE_TEST_TYPE;
4174 nodetype = XML_ELEMENT_NODE;
4175 goto search_nodes;
4176 case NODE_TYPE_PI:
4177 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004178 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004179 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004180 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004181 xmlXPathObjectPtr cur;
4182
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004183 /*
4184 * Specific case: search a PI by name.
4185 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004186 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004187 nodetest = NODE_TEST_PI;
4188 xmlXPathEvalLiteral(ctxt);
4189 CHECK_ERROR;
4190 if (CUR != ')')
4191 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004192 NEXT;
4193 xmlXPathStringFunction(ctxt, 1);
4194 CHECK_ERROR;
4195 cur = valuePop(ctxt);
4196 name = xmlStrdup(cur->stringval);
4197 xmlXPathFreeObject(cur);
4198 } else
4199 SKIP(2);
4200 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004201 goto search_nodes;
4202
4203 /*
4204 * Handling of the compund form: got the axis.
4205 */
4206 case AXIS_ANCESTOR:
4207 case AXIS_ANCESTOR_OR_SELF:
4208 case AXIS_ATTRIBUTE:
4209 case AXIS_CHILD:
4210 case AXIS_DESCENDANT:
4211 case AXIS_DESCENDANT_OR_SELF:
4212 case AXIS_FOLLOWING:
4213 case AXIS_FOLLOWING_SIBLING:
4214 case AXIS_NAMESPACE:
4215 case AXIS_PARENT:
4216 case AXIS_PRECEDING:
4217 case AXIS_PRECEDING_SIBLING:
4218 case AXIS_SELF:
4219 if ((CUR != ':') || (NXT(1) != ':')) {
4220 nodetest = NODE_TEST_NAME;
4221 break;
4222 }
4223 SKIP(2);
4224 axis = type;
4225 break;
4226
4227 /*
4228 * Default: abbreviated syntax the axis is AXIS_CHILD
4229 */
4230 default:
4231 nodetest = NODE_TEST_NAME;
4232 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004233parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004234 if (nodetest == NODE_TEST_NONE) {
4235 if (CUR == '*') {
4236 NEXT;
4237 nodetest = NODE_TEST_ALL;
4238 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004239 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004240 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004241 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004242 if (name == NULL) {
4243 ERROR(XPATH_EXPR_ERROR);
4244 }
4245 type = xmlXPathGetNameType(ctxt, name);
4246 switch (type) {
4247 /*
4248 * Simple case: no axis seach all given node types.
4249 */
4250 case NODE_TYPE_COMMENT:
4251 if ((CUR != '(') || (NXT(1) != ')')) break;
4252 SKIP(2);
4253 nodetest = NODE_TEST_TYPE;
4254 nodetype = XML_COMMENT_NODE;
4255 goto search_nodes;
4256 case NODE_TYPE_TEXT:
4257 if ((CUR != '(') || (NXT(1) != ')')) break;
4258 SKIP(2);
4259 nodetest = NODE_TEST_TYPE;
4260 nodetype = XML_TEXT_NODE;
4261 goto search_nodes;
4262 case NODE_TYPE_NODE:
4263 if ((CUR != '(') || (NXT(1) != ')')) {
4264 nodetest = NODE_TEST_NAME;
4265 break;
4266 }
4267 SKIP(2);
4268 nodetest = NODE_TEST_TYPE;
4269 nodetype = XML_ELEMENT_NODE;
4270 goto search_nodes;
4271 case NODE_TYPE_PI:
4272 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004273 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004274 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004275 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004276 xmlXPathObjectPtr cur;
4277
Daniel Veillardb05deb71999-08-10 19:04:08 +00004278 /*
4279 * Specific case: search a PI by name.
4280 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004281 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004282 nodetest = NODE_TEST_PI;
4283 xmlXPathEvalLiteral(ctxt);
4284 CHECK_ERROR;
4285 if (CUR != ')')
4286 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004287 NEXT;
4288 xmlXPathStringFunction(ctxt, 1);
4289 CHECK_ERROR;
4290 cur = valuePop(ctxt);
4291 name = xmlStrdup(cur->stringval);
4292 xmlXPathFreeObject(cur);
4293 } else
4294 SKIP(2);
4295 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004296 goto search_nodes;
4297 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004298 nodetest = NODE_TEST_NAME;
4299 }
4300 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4301 NEXT;
4302 prefix = name;
4303 if (CUR == '*') {
4304 NEXT;
4305 nodetest = NODE_TEST_ALL;
4306 } else
4307 name = xmlXPathParseNCName(ctxt);
4308 } else if (name == NULL)
4309 ERROR(XPATH_EXPR_ERROR);
4310 }
4311
4312search_nodes:
4313
4314#ifdef DEBUG_STEP
4315 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4316#endif
4317 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4318 prefix, name);
4319 if (ctxt->context->nodelist != NULL)
4320 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4321 ctxt->context->nodelist = newset;
4322 ctxt->context->node = NULL;
4323#ifdef DEBUG_STEP
4324 fprintf(xmlXPathDebug, "Basis : ");
4325 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4326#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004327 if (name != NULL) xmlFree(name);
4328 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004329}
4330
4331/**
4332 * xmlXPathEvalStep:
4333 * @ctxt: the XPath Parser context
4334 *
4335 * [4] Step ::= Basis Predicate*
4336 * | AbbreviatedStep
4337 * [12] AbbreviatedStep ::= '.'
4338 * | '..'
4339 *
4340 * Evaluate one step in a Location Path
4341 * A location step of . is short for self::node(). This is
4342 * particularly useful in conjunction with //. For example, the
4343 * location path .//para is short for
4344 * self::node()/descendant-or-self::node()/child::para
4345 * and so will select all para descendant elements of the context
4346 * node.
4347 * Similarly, a location step of .. is short for parent::node().
4348 * For example, ../title is short for parent::node()/child::title
4349 * and so will select the title children of the parent of the context
4350 * node.
4351 */
4352void
4353xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4354 xmlNodeSetPtr newset = NULL;
4355
Daniel Veillard00fdf371999-10-08 09:40:39 +00004356 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004357 if ((CUR == '.') && (NXT(1) == '.')) {
4358 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004359 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004360 if (ctxt->context->nodelist == NULL) {
4361 STRANGE
4362 xmlXPathRoot(ctxt);
4363 }
4364 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4365 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4366 if (ctxt->context->nodelist != NULL)
4367 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4368 ctxt->context->nodelist = newset;
4369 ctxt->context->node = NULL;
4370 } else if (CUR == '.') {
4371 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004372 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004373 } else {
4374 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004375 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004376 while (CUR == '[') {
4377 xmlXPathEvalPredicate(ctxt);
4378 }
4379 }
4380#ifdef DEBUG_STEP
4381 fprintf(xmlXPathDebug, "Step : ");
4382 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4383#endif
4384}
4385
4386/**
4387 * xmlXPathEvalRelativeLocationPath:
4388 * @ctxt: the XPath Parser context
4389 *
4390 * [3] RelativeLocationPath ::= Step
4391 * | RelativeLocationPath '/' Step
4392 * | AbbreviatedRelativeLocationPath
4393 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4394 *
4395 */
4396void
4397xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4398 xmlNodeSetPtr newset = NULL;
4399
Daniel Veillard00fdf371999-10-08 09:40:39 +00004400 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004401 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004402 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004403 while (CUR == '/') {
4404 if ((CUR == '/') && (NXT(1) == '/')) {
4405 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004406 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004407 if (ctxt->context->nodelist == NULL) {
4408 STRANGE
4409 xmlXPathRoot(ctxt);
4410 }
4411 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4412 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4413 if (ctxt->context->nodelist != NULL)
4414 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4415 ctxt->context->nodelist = newset;
4416 ctxt->context->node = NULL;
4417 xmlXPathEvalStep(ctxt);
4418 } else if (CUR == '/') {
4419 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004420 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004421 xmlXPathEvalStep(ctxt);
4422 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004423 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004424 }
4425}
4426
4427/**
4428 * xmlXPathEvalLocationPath:
4429 * @ctxt: the XPath Parser context
4430 *
4431 * [1] LocationPath ::= RelativeLocationPath
4432 * | AbsoluteLocationPath
4433 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4434 * | AbbreviatedAbsoluteLocationPath
4435 * [10] AbbreviatedAbsoluteLocationPath ::=
4436 * '//' RelativeLocationPath
4437 *
4438 * // is short for /descendant-or-self::node()/. For example,
4439 * //para is short for /descendant-or-self::node()/child::para and
4440 * so will select any para element in the document (even a para element
4441 * that is a document element will be selected by //para since the
4442 * document element node is a child of the root node); div//para is
4443 * short for div/descendant-or-self::node()/child::para and so will
4444 * select all para descendants of div children.
4445 */
4446void
4447xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4448 xmlNodeSetPtr newset = NULL;
4449
Daniel Veillard00fdf371999-10-08 09:40:39 +00004450 SKIP_BLANKS;
4451 if (CUR != '/') {
4452 xmlXPathEvalRelativeLocationPath(ctxt);
4453 } else {
4454 while (CUR == '/') {
4455 if ((CUR == '/') && (NXT(1) == '/')) {
4456 SKIP(2);
4457 SKIP_BLANKS;
4458 if (ctxt->context->nodelist == NULL)
4459 xmlXPathRoot(ctxt);
4460 newset = xmlXPathNodeCollectAndTest(ctxt,
4461 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4462 XML_ELEMENT_NODE, NULL, NULL);
4463 if (ctxt->context->nodelist != NULL)
4464 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4465 ctxt->context->nodelist = newset;
4466 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004467 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004468 } else if (CUR == '/') {
4469 NEXT;
4470 SKIP_BLANKS;
4471 xmlXPathRoot(ctxt);
4472 if (CUR != 0)
4473 xmlXPathEvalRelativeLocationPath(ctxt);
4474 } else {
4475 xmlXPathEvalRelativeLocationPath(ctxt);
4476 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004477 }
4478 }
4479}
4480
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004481/**
4482 * xmlXPathEval:
4483 * @str: the XPath expression
4484 * @ctxt: the XPath context
4485 *
4486 * Evaluate the XPath Location Path in the given context.
4487 *
4488 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4489 * the caller has to free the object.
4490 */
4491xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004492xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004493 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004494 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004495 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004496
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004497 xmlXPathInit();
4498
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004499 CHECK_CONTEXT
4500
4501 if (xmlXPathDebug == NULL)
4502 xmlXPathDebug = stderr;
4503 pctxt = xmlXPathNewParserContext(str, ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004504 if (str[0] == '/')
4505 xmlXPathRoot(pctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004506 xmlXPathEvalLocationPath(pctxt);
4507
Daniel Veillardb96e6431999-08-29 21:02:19 +00004508 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004509 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004510 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004511 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004512 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004513 stack++;
4514 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004515 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004516 if (stack != 0) {
4517 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4518 stack);
4519 }
4520 if (pctxt->error == XPATH_EXPRESSION_OK)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004521 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004522 else
4523 res = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004524 xmlXPathFreeParserContext(pctxt);
4525 return(res);
4526}
4527
4528/**
4529 * xmlXPathEvalExpression:
4530 * @str: the XPath expression
4531 * @ctxt: the XPath context
4532 *
4533 * Evaluate the XPath expression in the given context.
4534 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004535 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004536 * the caller has to free the object.
4537 */
4538xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004539xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004540 xmlXPathParserContextPtr pctxt;
4541 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004542 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004543
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004544 xmlXPathInit();
4545
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004546 CHECK_CONTEXT
4547
4548 if (xmlXPathDebug == NULL)
4549 xmlXPathDebug = stderr;
4550 pctxt = xmlXPathNewParserContext(str, ctxt);
4551 xmlXPathEvalExpr(pctxt);
4552
4553 res = valuePop(pctxt);
4554 do {
4555 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004556 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004557 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004558 stack++;
4559 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004560 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004561 if (stack != 0) {
4562 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4563 stack);
4564 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004565 xmlXPathFreeParserContext(pctxt);
4566 return(res);
4567}
4568