blob: 7f2a5894a8f2994063ee12ed83580e649f8d9bf1 [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 Veillarddbfd6411999-12-28 16:35:14 +00001491 if ((ctxt->context->node->type == XML_DOCUMENT_NODE) ||
1492 (ctxt->context->node->type == XML_HTML_DOCUMENT_NODE))
1493 return(((xmlDocPtr) ctxt->context->node)->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001494 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001495 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001496 if ((cur->type == XML_DOCUMENT_NODE) ||
1497 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001498 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001499 return(cur->next);
1500}
1501
1502/**
1503 * mlXPathNextDescendant:
1504 * @ctxt: the XPath Parser context
1505 * @cur: the current node in the traversal
1506 *
1507 * Traversal function for the "descendant" direction
1508 * the descendant axis contains the descendants of the context node in document
1509 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001510 *
1511 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001512 */
1513xmlNodePtr
1514xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001515 if (cur == NULL) {
1516 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1517 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001518 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001519 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001520
1521 if (cur->childs != NULL) return(cur->childs);
1522 if (cur->next != NULL) return(cur->next);
1523
1524 do {
1525 cur = cur->parent;
1526 if (cur == NULL) return(NULL);
1527 if (cur == ctxt->context->node) return(NULL);
1528 if (cur->next != NULL) {
1529 cur = cur->next;
1530 return(cur);
1531 }
1532 } while (cur != NULL);
1533 return(cur);
1534}
1535
1536/**
1537 * mlXPathNextDescendantOrSelf:
1538 * @ctxt: the XPath Parser context
1539 * @cur: the current node in the traversal
1540 *
1541 * Traversal function for the "descendant-or-self" direction
1542 * the descendant-or-self axis contains the context node and the descendants
1543 * of the context node in document order; thus the context node is the first
1544 * node on the axis, and the first child of the context node is the second node
1545 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001546 *
1547 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001548 */
1549xmlNodePtr
1550xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1551 if (cur == NULL)
1552 return(ctxt->context->node);
1553
Daniel Veillardb05deb71999-08-10 19:04:08 +00001554 if (cur == (xmlNodePtr) ctxt->context->doc)
1555 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001556 if (cur->childs != NULL) return(cur->childs);
1557 if (cur->next != NULL) return(cur->next);
1558
1559 do {
1560 cur = cur->parent;
1561 if (cur == NULL) return(NULL);
1562 if (cur == ctxt->context->node) return(NULL);
1563 if (cur->next != NULL) {
1564 cur = cur->next;
1565 return(cur);
1566 }
1567 } while (cur != NULL);
1568 return(cur);
1569}
1570
1571/**
1572 * xmlXPathNextParent:
1573 * @ctxt: the XPath Parser context
1574 * @cur: the current node in the traversal
1575 *
1576 * Traversal function for the "parent" direction
1577 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001578 *
1579 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001580 */
1581xmlNodePtr
1582xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1583 /*
1584 * !!!!!!!!!!!!!
1585 * the parent of an attribute or namespace node is the element
1586 * to which the attribute or namespace node is attached
1587 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001588 if (cur == NULL) {
1589 if (ctxt->context->node->parent == NULL)
1590 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001591 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001592 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001593 return(NULL);
1594}
1595
1596/**
1597 * xmlXPathNextAncestor:
1598 * @ctxt: the XPath Parser context
1599 * @cur: the current node in the traversal
1600 *
1601 * Traversal function for the "ancestor" direction
1602 * the ancestor axis contains the ancestors of the context node; the ancestors
1603 * of the context node consist of the parent of context node and the parent's
1604 * parent and so on; the nodes are ordered in reverse document order; thus the
1605 * parent is the first node on the axis, and the parent's parent is the second
1606 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001607 *
1608 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001609 */
1610xmlNodePtr
1611xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1612 /*
1613 * !!!!!!!!!!!!!
1614 * the parent of an attribute or namespace node is the element
1615 * to which the attribute or namespace node is attached
1616 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001617 if (cur == NULL) {
1618 if (ctxt->context->node->parent == NULL)
1619 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001620 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001621 }
1622 if (cur == ctxt->context->doc->root)
1623 return((xmlNodePtr) ctxt->context->doc);
1624 if (cur == (xmlNodePtr) ctxt->context->doc)
1625 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001626 return(cur->parent);
1627}
1628
1629/**
1630 * xmlXPathNextAncestorOrSelf:
1631 * @ctxt: the XPath Parser context
1632 * @cur: the current node in the traversal
1633 *
1634 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001635 * he ancestor-or-self axis contains the context node and ancestors of
1636 * the context node in reverse document order; thus the context node is
1637 * the first node on the axis, and the context node's parent the second;
1638 * parent here is defined the same as with the parent axis.
1639 *
1640 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001641 */
1642xmlNodePtr
1643xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1644 /*
1645 * !!!!!!!!!!!!!
1646 * the parent of an attribute or namespace node is the element
1647 * to which the attribute or namespace node is attached
1648 */
1649 if (cur == NULL)
1650 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001651 if (cur == ctxt->context->doc->root)
1652 return((xmlNodePtr) ctxt->context->doc);
1653 if (cur == (xmlNodePtr) ctxt->context->doc)
1654 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001655 return(cur->parent);
1656}
1657
1658/**
1659 * xmlXPathNextFollowingSibling:
1660 * @ctxt: the XPath Parser context
1661 * @cur: the current node in the traversal
1662 *
1663 * Traversal function for the "following-sibling" direction
1664 * The following-sibling axis contains the following siblings of the context
1665 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001666 *
1667 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001668 */
1669xmlNodePtr
1670xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001671 if (cur == (xmlNodePtr) ctxt->context->doc)
1672 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001673 if (cur == NULL)
1674 return(ctxt->context->node->next);
1675 return(cur->next);
1676}
1677
1678/**
1679 * xmlXPathNextPrecedingSibling:
1680 * @ctxt: the XPath Parser context
1681 * @cur: the current node in the traversal
1682 *
1683 * Traversal function for the "preceding-sibling" direction
1684 * The preceding-sibling axis contains the preceding siblings of the context
1685 * node in reverse document order; the first preceding sibling is first on the
1686 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001687 *
1688 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001689 */
1690xmlNodePtr
1691xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001692 if (cur == (xmlNodePtr) ctxt->context->doc)
1693 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001694 if (cur == NULL)
1695 return(ctxt->context->node->prev);
1696 return(cur->prev);
1697}
1698
1699/**
1700 * xmlXPathNextFollowing:
1701 * @ctxt: the XPath Parser context
1702 * @cur: the current node in the traversal
1703 *
1704 * Traversal function for the "following" direction
1705 * The following axis contains all nodes in the same document as the context
1706 * node that are after the context node in document order, excluding any
1707 * descendants and excluding attribute nodes and namespace nodes; the nodes
1708 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001709 *
1710 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001711 */
1712xmlNodePtr
1713xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001714 if (cur == (xmlNodePtr) ctxt->context->doc)
1715 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001716 if (cur == NULL)
1717 return(ctxt->context->node->next);; /* !!!!!!!!! */
1718 if (cur->childs != NULL) return(cur->childs);
1719 if (cur->next != NULL) return(cur->next);
1720
1721 do {
1722 cur = cur->parent;
1723 if (cur == NULL) return(NULL);
1724 if (cur == ctxt->context->doc->root) return(NULL);
1725 if (cur->next != NULL) {
1726 cur = cur->next;
1727 return(cur);
1728 }
1729 } while (cur != NULL);
1730 return(cur);
1731}
1732
1733/**
1734 * xmlXPathNextPreceding:
1735 * @ctxt: the XPath Parser context
1736 * @cur: the current node in the traversal
1737 *
1738 * Traversal function for the "preceding" direction
1739 * the preceding axis contains all nodes in the same document as the context
1740 * node that are before the context node in document order, excluding any
1741 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1742 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001743 *
1744 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001745 */
1746xmlNodePtr
1747xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001748 if (cur == (xmlNodePtr) ctxt->context->doc)
1749 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001750 if (cur == NULL)
1751 return(ctxt->context->node->prev); /* !!!!!!!!! */
1752 if (cur->last != NULL) return(cur->last);
1753 if (cur->prev != NULL) return(cur->prev);
1754
1755 do {
1756 cur = cur->parent;
1757 if (cur == NULL) return(NULL);
1758 if (cur == ctxt->context->doc->root) return(NULL);
1759 if (cur->prev != NULL) {
1760 cur = cur->prev;
1761 return(cur);
1762 }
1763 } while (cur != NULL);
1764 return(cur);
1765}
1766
1767/**
1768 * xmlXPathNextNamespace:
1769 * @ctxt: the XPath Parser context
1770 * @cur: the current attribute in the traversal
1771 *
1772 * Traversal function for the "namespace" direction
1773 * the namespace axis contains the namespace nodes of the context node;
1774 * the order of nodes on this axis is implementation-defined; the axis will
1775 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001776 *
1777 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001778 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001779xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001780xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001781 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1782 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001783 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001784 ctxt->context->namespaces =
1785 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1786 if (ctxt->context->namespaces == NULL) return(NULL);
1787 ctxt->context->nsNr = 0;
1788 }
1789 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001790}
1791
1792/**
1793 * xmlXPathNextAttribute:
1794 * @ctxt: the XPath Parser context
1795 * @cur: the current attribute in the traversal
1796 *
1797 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001798 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001799 *
1800 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001801 */
1802xmlAttrPtr
1803xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001804 if (cur == NULL) {
1805 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1806 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001807 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001808 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001809 return(cur->next);
1810}
1811
1812/************************************************************************
1813 * *
1814 * NodeTest Functions *
1815 * *
1816 ************************************************************************/
1817
1818#define NODE_TEST_NONE 0
1819#define NODE_TEST_TYPE 1
1820#define NODE_TEST_PI 2
1821#define NODE_TEST_ALL 3
1822#define NODE_TEST_NS 4
1823#define NODE_TEST_NAME 5
1824
1825#define NODE_TYPE_COMMENT 50
1826#define NODE_TYPE_TEXT 51
1827#define NODE_TYPE_PI 52
1828#define NODE_TYPE_NODE 53
1829
1830#define IS_FUNCTION 200
1831
1832/**
1833 * xmlXPathNodeCollectAndTest:
1834 * @ctxt: the XPath Parser context
1835 * @cur: the current node to test
1836 *
1837 * This is the function implementing a step: based on the current list
1838 * of nodes, it builds up a new list, looking at all nodes under that
1839 * axis and selecting them.
1840 *
1841 * Returns the new NodeSet resulting from the search.
1842 */
1843xmlNodeSetPtr
1844xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001845 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001846#ifdef DEBUG_STEP
1847 int n = 0, t = 0;
1848#endif
1849 int i;
1850 xmlNodeSetPtr ret;
1851 xmlXPathTraversalFunction next = NULL;
1852 xmlNodePtr cur = NULL;
1853
1854 if (ctxt->context->nodelist == NULL) {
1855 if (ctxt->context->node == NULL) {
1856 fprintf(xmlXPathDebug,
1857 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1858 __FILE__, __LINE__);
1859 return(NULL);
1860 }
1861 STRANGE
1862 return(NULL);
1863 }
1864#ifdef DEBUG_STEP
1865 fprintf(xmlXPathDebug, "new step : ");
1866#endif
1867 switch (axis) {
1868 case AXIS_ANCESTOR:
1869#ifdef DEBUG_STEP
1870 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1871#endif
1872 next = xmlXPathNextAncestor; break;
1873 case AXIS_ANCESTOR_OR_SELF:
1874#ifdef DEBUG_STEP
1875 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1876#endif
1877 next = xmlXPathNextAncestorOrSelf; break;
1878 case AXIS_ATTRIBUTE:
1879#ifdef DEBUG_STEP
1880 fprintf(xmlXPathDebug, "axis 'attributes' ");
1881#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001882 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001883 break;
1884 case AXIS_CHILD:
1885#ifdef DEBUG_STEP
1886 fprintf(xmlXPathDebug, "axis 'child' ");
1887#endif
1888 next = xmlXPathNextChild; break;
1889 case AXIS_DESCENDANT:
1890#ifdef DEBUG_STEP
1891 fprintf(xmlXPathDebug, "axis 'descendant' ");
1892#endif
1893 next = xmlXPathNextDescendant; break;
1894 case AXIS_DESCENDANT_OR_SELF:
1895#ifdef DEBUG_STEP
1896 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1897#endif
1898 next = xmlXPathNextDescendantOrSelf; break;
1899 case AXIS_FOLLOWING:
1900#ifdef DEBUG_STEP
1901 fprintf(xmlXPathDebug, "axis 'following' ");
1902#endif
1903 next = xmlXPathNextFollowing; break;
1904 case AXIS_FOLLOWING_SIBLING:
1905#ifdef DEBUG_STEP
1906 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1907#endif
1908 next = xmlXPathNextFollowingSibling; break;
1909 case AXIS_NAMESPACE:
1910#ifdef DEBUG_STEP
1911 fprintf(xmlXPathDebug, "axis 'namespace' ");
1912#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001913 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001914 break;
1915 case AXIS_PARENT:
1916#ifdef DEBUG_STEP
1917 fprintf(xmlXPathDebug, "axis 'parent' ");
1918#endif
1919 next = xmlXPathNextParent; break;
1920 case AXIS_PRECEDING:
1921#ifdef DEBUG_STEP
1922 fprintf(xmlXPathDebug, "axis 'preceding' ");
1923#endif
1924 next = xmlXPathNextPreceding; break;
1925 case AXIS_PRECEDING_SIBLING:
1926#ifdef DEBUG_STEP
1927 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1928#endif
1929 next = xmlXPathNextPrecedingSibling; break;
1930 case AXIS_SELF:
1931#ifdef DEBUG_STEP
1932 fprintf(xmlXPathDebug, "axis 'self' ");
1933#endif
1934 next = xmlXPathNextSelf; break;
1935 }
1936 if (next == NULL) return(NULL);
1937 ret = xmlXPathNodeSetCreate(NULL);
1938#ifdef DEBUG_STEP
1939 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1940 ctxt->context->nodelist->nodeNr);
1941 switch (test) {
1942 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001943 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001944 break;
1945 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001946 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001947 break;
1948 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001949 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001950 break;
1951 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001952 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001953 break;
1954 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001955 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001956 prefix);
1957 break;
1958 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001959 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001960 if (prefix != NULL)
1961 fprintf(xmlXPathDebug, " with namespace %s\n",
1962 prefix);
1963 break;
1964 }
1965 fprintf(xmlXPathDebug, "Testing : ");
1966#endif
1967 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1968 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1969
1970 cur = NULL;
1971 do {
1972 cur = next(ctxt, cur);
1973 if (cur == NULL) break;
1974#ifdef DEBUG_STEP
1975 t++;
1976 fprintf(xmlXPathDebug, " %s", cur->name);
1977#endif
1978 switch (test) {
1979 case NODE_TEST_NONE:
1980 STRANGE
1981 return(NULL);
1982 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001983 if ((cur->type == type) ||
1984 ((type == XML_ELEMENT_NODE) &&
1985 ((cur->type == XML_DOCUMENT_NODE) ||
1986 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001987#ifdef DEBUG_STEP
1988 n++;
1989#endif
1990 xmlXPathNodeSetAdd(ret, cur);
1991 }
1992 break;
1993 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001994 if (cur->type == XML_PI_NODE) {
1995 if ((name != NULL) &&
1996 (xmlStrcmp(name, cur->name)))
1997 break;
1998#ifdef DEBUG_STEP
1999 n++;
2000#endif
2001 xmlXPathNodeSetAdd(ret, cur);
2002 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002003 break;
2004 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002005 if ((cur->type == XML_ELEMENT_NODE) ||
2006 (cur->type == XML_ATTRIBUTE_NODE)) {
2007 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002008#ifdef DEBUG_STEP
2009 n++;
2010#endif
2011 xmlXPathNodeSetAdd(ret, cur);
2012 }
2013 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002014 case NODE_TEST_NS: {
2015 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002016 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002017 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002018 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002019 switch (cur->type) {
2020 case XML_ELEMENT_NODE:
2021 if (!xmlStrcmp(name, cur->name) &&
2022 (((prefix == NULL) ||
2023 ((cur->ns != NULL) &&
2024 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002025#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002026 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002027#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002028 xmlXPathNodeSetAdd(ret, cur);
2029 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002030 break;
2031 case XML_ATTRIBUTE_NODE: {
2032 xmlAttrPtr attr = (xmlAttrPtr) cur;
2033 if (!xmlStrcmp(name, attr->name)) {
2034#ifdef DEBUG_STEP
2035 n++;
2036#endif
2037 xmlXPathNodeSetAdd(ret, cur);
2038 }
2039 break;
2040 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002041 default:
2042 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002043 }
2044 break;
2045
2046 }
2047 } while (cur != NULL);
2048 }
2049#ifdef DEBUG_STEP
2050 fprintf(xmlXPathDebug,
2051 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2052#endif
2053 return(ret);
2054}
2055
2056
2057/************************************************************************
2058 * *
2059 * Implicit tree core function library *
2060 * *
2061 ************************************************************************/
2062
2063/**
2064 * xmlXPathRoot:
2065 * @ctxt: the XPath Parser context
2066 *
2067 * Initialize the context to the root of the document
2068 */
2069void
2070xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2071 if (ctxt->context->nodelist != NULL)
2072 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002073 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2074 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002075}
2076
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002077/************************************************************************
2078 * *
2079 * The explicit core function library *
2080 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2081 * *
2082 ************************************************************************/
2083
2084
2085/**
2086 * xmlXPathLastFunction:
2087 * @ctxt: the XPath Parser context
2088 *
2089 * Implement the last() XPath function
2090 * The last function returns the number of nodes in the context node list.
2091 */
2092void
2093xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2094 CHECK_ARITY(0);
2095 if ((ctxt->context->nodelist == NULL) ||
2096 (ctxt->context->node == NULL) ||
2097 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002098 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002099 } else {
2100 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002101 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002102 }
2103}
2104
2105/**
2106 * xmlXPathPositionFunction:
2107 * @ctxt: the XPath Parser context
2108 *
2109 * Implement the position() XPath function
2110 * The position function returns the position of the context node in the
2111 * context node list. The first position is 1, and so the last positionr
2112 * will be equal to last().
2113 */
2114void
2115xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2116 int i;
2117
2118 CHECK_ARITY(0);
2119 if ((ctxt->context->nodelist == NULL) ||
2120 (ctxt->context->node == NULL) ||
2121 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002122 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002123 }
2124 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2125 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002126 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002127 return;
2128 }
2129 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002130 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002131}
2132
2133/**
2134 * xmlXPathCountFunction:
2135 * @ctxt: the XPath Parser context
2136 *
2137 * Implement the count() XPath function
2138 */
2139void
2140xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2141 xmlXPathObjectPtr cur;
2142
2143 CHECK_ARITY(1);
2144 CHECK_TYPE(XPATH_NODESET);
2145 cur = valuePop(ctxt);
2146
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002147 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002148 xmlXPathFreeObject(cur);
2149}
2150
2151/**
2152 * xmlXPathIdFunction:
2153 * @ctxt: the XPath Parser context
2154 *
2155 * Implement the id() XPath function
2156 * The id function selects elements by their unique ID
2157 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2158 * then the result is the union of the result of applying id to the
2159 * string value of each of the nodes in the argument node-set. When the
2160 * argument to id is of any other type, the argument is converted to a
2161 * string as if by a call to the string function; the string is split
2162 * into a whitespace-separated list of tokens (whitespace is any sequence
2163 * of characters matching the production S); the result is a node-set
2164 * containing the elements in the same document as the context node that
2165 * have a unique ID equal to any of the tokens in the list.
2166 */
2167void
2168xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002169 const xmlChar *tokens;
2170 const xmlChar *cur;
2171 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002172 xmlAttrPtr attr;
2173 xmlNodePtr elem = NULL;
2174 xmlXPathObjectPtr ret, obj;
2175
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002176 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002177 obj = valuePop(ctxt);
2178 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2179 if (obj->type == XPATH_NODESET) {
2180 TODO /* ID function in case of NodeSet */
2181 }
2182 if (obj->type != XPATH_STRING) {
2183 valuePush(ctxt, obj);
2184 xmlXPathStringFunction(ctxt, 1);
2185 obj = valuePop(ctxt);
2186 if (obj->type != XPATH_STRING) {
2187 xmlXPathFreeObject(obj);
2188 return;
2189 }
2190 }
2191 tokens = obj->stringval;
2192
2193 ret = xmlXPathNewNodeSet(NULL);
2194 valuePush(ctxt, ret);
2195 if (tokens == NULL) {
2196 xmlXPathFreeObject(obj);
2197 return;
2198 }
2199
2200 cur = tokens;
2201
2202 while (IS_BLANK(*cur)) cur++;
2203 while (*cur != 0) {
2204 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2205 (*cur == '.') || (*cur == '-') ||
2206 (*cur == '_') || (*cur == ':') ||
2207 (IS_COMBINING(*cur)) ||
2208 (IS_EXTENDER(*cur)))
2209 cur++;
2210
2211 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2212
2213 ID = xmlStrndup(tokens, cur - tokens);
2214 attr = xmlGetID(ctxt->context->doc, ID);
2215 if (attr != NULL) {
2216 elem = attr->node;
2217 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2218 }
2219 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002220 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002221
2222 while (IS_BLANK(*cur)) cur++;
2223 tokens = cur;
2224 }
2225 xmlXPathFreeObject(obj);
2226 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002227}
2228
2229/**
2230 * xmlXPathLocalPartFunction:
2231 * @ctxt: the XPath Parser context
2232 *
2233 * Implement the local-part() XPath function
2234 * The local-part function returns a string containing the local part
2235 * of the name of the node in the argument node-set that is first in
2236 * document order. If the node-set is empty or the first node has no
2237 * name, an empty string is returned. If the argument is omitted it
2238 * defaults to the context node.
2239 */
2240void
2241xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2242 xmlXPathObjectPtr cur;
2243
2244 CHECK_ARITY(1);
2245 CHECK_TYPE(XPATH_NODESET);
2246 cur = valuePop(ctxt);
2247
2248 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002249 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002250 } else {
2251 int i = 0; /* Should be first in document order !!!!! */
2252 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2253 }
2254 xmlXPathFreeObject(cur);
2255}
2256
2257/**
2258 * xmlXPathNamespaceFunction:
2259 * @ctxt: the XPath Parser context
2260 *
2261 * Implement the namespace() XPath function
2262 * The namespace function returns a string containing the namespace URI
2263 * of the expanded name of the node in the argument node-set that is
2264 * first in document order. If the node-set is empty, the first node has
2265 * no name, or the expanded name has no namespace URI, an empty string
2266 * is returned. If the argument is omitted it defaults to the context node.
2267 */
2268void
2269xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2270 xmlXPathObjectPtr cur;
2271
Daniel Veillardb96e6431999-08-29 21:02:19 +00002272 if (nargs == 0) {
2273 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2274 nargs = 1;
2275 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002276 CHECK_ARITY(1);
2277 CHECK_TYPE(XPATH_NODESET);
2278 cur = valuePop(ctxt);
2279
2280 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002281 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002282 } else {
2283 int i = 0; /* Should be first in document order !!!!! */
2284
2285 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002286 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002287 else
2288 valuePush(ctxt, xmlXPathNewString(
2289 cur->nodesetval->nodeTab[i]->ns->href));
2290 }
2291 xmlXPathFreeObject(cur);
2292}
2293
2294/**
2295 * xmlXPathNameFunction:
2296 * @ctxt: the XPath Parser context
2297 *
2298 * Implement the name() XPath function
2299 * The name function returns a string containing a QName representing
2300 * the name of the node in the argument node-set that is first in documenti
2301 * order. The QName must represent the name with respect to the namespace
2302 * declarations in effect on the node whose name is being represented.
2303 * Typically, this will be the form in which the name occurred in the XML
2304 * source. This need not be the case if there are namespace declarations
2305 * in effect on the node that associate multiple prefixes with the same
2306 * namespace. However, an implementation may include information about
2307 * the original prefix in its representation of nodes; in this case, an
2308 * implementation can ensure that the returned string is always the same
2309 * as the QName used in the XML source. If the argument it omitted it
2310 * defaults to the context node.
2311 * Libxml keep the original prefix so the "real qualified name" used is
2312 * returned.
2313 */
2314void
2315xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2316 xmlXPathObjectPtr cur;
2317
2318 CHECK_ARITY(1);
2319 CHECK_TYPE(XPATH_NODESET);
2320 cur = valuePop(ctxt);
2321
2322 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002323 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002324 } else {
2325 int i = 0; /* Should be first in document order !!!!! */
2326
2327 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2328 valuePush(ctxt, xmlXPathNewString(
2329 cur->nodesetval->nodeTab[i]->name));
2330
2331 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002332 char name[2000];
2333 sprintf(name, "%s:%s",
2334 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2335 (char *) cur->nodesetval->nodeTab[i]->name);
2336 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002337 }
2338 }
2339 xmlXPathFreeObject(cur);
2340}
2341
2342/**
2343 * xmlXPathStringFunction:
2344 * @ctxt: the XPath Parser context
2345 *
2346 * Implement the string() XPath function
2347 * he string function converts an object to a string as follows:
2348 * - A node-set is converted to a string by returning the value of
2349 * the node in the node-set that is first in document order.
2350 * If the node-set is empty, an empty string is returned.
2351 * - A number is converted to a string as follows
2352 * + NaN is converted to the string NaN
2353 * + positive zero is converted to the string 0
2354 * + negative zero is converted to the string 0
2355 * + positive infinity is converted to the string Infinity
2356 * + negative infinity is converted to the string -Infinity
2357 * + if the number is an integer, the number is represented in
2358 * decimal form as a Number with no decimal point and no leading
2359 * zeros, preceded by a minus sign (-) if the number is negative
2360 * + otherwise, the number is represented in decimal form as a
2361 * Number including a decimal point with at least one digit
2362 * before the decimal point and at least one digit after the
2363 * decimal point, preceded by a minus sign (-) if the number
2364 * is negative; there must be no leading zeros before the decimal
2365 * point apart possibly from the one required digit immediatelyi
2366 * before the decimal point; beyond the one required digit
2367 * after the decimal point there must be as many, but only as
2368 * many, more digits as are needed to uniquely distinguish the
2369 * number from all other IEEE 754 numeric values.
2370 * - The boolean false value is converted to the string false.
2371 * The boolean true value is converted to the string true.
2372 */
2373void
2374xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2375 xmlXPathObjectPtr cur;
2376
2377 CHECK_ARITY(1);
2378 cur = valuePop(ctxt);
2379 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2380 switch (cur->type) {
2381 case XPATH_NODESET:
2382 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002383 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002384 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002385 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002386 int i = 0; /* Should be first in document order !!!!! */
2387 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2388 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002389 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002390 }
2391 xmlXPathFreeObject(cur);
2392 return;
2393 case XPATH_STRING:
2394 valuePush(ctxt, cur);
2395 return;
2396 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002397 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2398 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002399 xmlXPathFreeObject(cur);
2400 return;
2401 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002402 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002403
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002404 if (isnan(cur->floatval))
2405 sprintf(buf, "NaN");
2406 else if (isinf(cur->floatval) > 0)
2407 sprintf(buf, "+Infinity");
2408 else if (isinf(cur->floatval) < 0)
2409 sprintf(buf, "-Infinity");
2410 else
2411 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002412 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002413 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002414 return;
2415 }
2416 }
2417 STRANGE
2418}
2419
2420/**
2421 * xmlXPathStringLengthFunction:
2422 * @ctxt: the XPath Parser context
2423 *
2424 * Implement the string-length() XPath function
2425 * The string-length returns the number of characters in the string
2426 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2427 * the context node converted to a string, in other words the value
2428 * of the context node.
2429 */
2430void
2431xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2432 xmlXPathObjectPtr cur;
2433
2434 if (nargs == 0) {
2435 if (ctxt->context->node == NULL) {
2436 valuePush(ctxt, xmlXPathNewFloat(0));
2437 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002438 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002439
2440 content = xmlNodeGetContent(ctxt->context->node);
2441 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002442 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002443 }
2444 return;
2445 }
2446 CHECK_ARITY(1);
2447 CHECK_TYPE(XPATH_STRING);
2448 cur = valuePop(ctxt);
2449 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2450 xmlXPathFreeObject(cur);
2451}
2452
2453/**
2454 * xmlXPathConcatFunction:
2455 * @ctxt: the XPath Parser context
2456 *
2457 * Implement the concat() XPath function
2458 * The concat function returns the concatenation of its arguments.
2459 */
2460void
2461xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2462 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002463 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002464
2465 if (nargs < 2) {
2466 CHECK_ARITY(2);
2467 }
2468
2469 cur = valuePop(ctxt);
2470 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2471 xmlXPathFreeObject(cur);
2472 return;
2473 }
2474 nargs--;
2475
2476 while (nargs > 0) {
2477 new = valuePop(ctxt);
2478 if ((new == NULL) || (new->type != XPATH_STRING)) {
2479 xmlXPathFreeObject(new);
2480 xmlXPathFreeObject(cur);
2481 ERROR(XPATH_INVALID_TYPE);
2482 }
2483 tmp = xmlStrcat(new->stringval, cur->stringval);
2484 new->stringval = cur->stringval;
2485 cur->stringval = tmp;
2486
2487 xmlXPathFreeObject(new);
2488 nargs--;
2489 }
2490 valuePush(ctxt, cur);
2491}
2492
2493/**
2494 * xmlXPathContainsFunction:
2495 * @ctxt: the XPath Parser context
2496 *
2497 * Implement the contains() XPath function
2498 * The contains function returns true if the first argument string
2499 * contains the second argument string, and otherwise returns false.
2500 */
2501void
2502xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2503 xmlXPathObjectPtr hay, needle;
2504
2505 CHECK_ARITY(2);
2506 CHECK_TYPE(XPATH_STRING);
2507 needle = valuePop(ctxt);
2508 hay = valuePop(ctxt);
2509 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2510 xmlXPathFreeObject(hay);
2511 xmlXPathFreeObject(needle);
2512 ERROR(XPATH_INVALID_TYPE);
2513 }
2514 if (xmlStrstr(hay->stringval, needle->stringval))
2515 valuePush(ctxt, xmlXPathNewBoolean(1));
2516 else
2517 valuePush(ctxt, xmlXPathNewBoolean(0));
2518 xmlXPathFreeObject(hay);
2519 xmlXPathFreeObject(needle);
2520}
2521
2522/**
2523 * xmlXPathStartsWithFunction:
2524 * @ctxt: the XPath Parser context
2525 *
2526 * Implement the starts-with() XPath function
2527 * The starts-with function returns true if the first argument string
2528 * starts with the second argument string, and otherwise returns false.
2529 */
2530void
2531xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2532 xmlXPathObjectPtr hay, needle;
2533 int n;
2534
2535 CHECK_ARITY(2);
2536 CHECK_TYPE(XPATH_STRING);
2537 needle = valuePop(ctxt);
2538 hay = valuePop(ctxt);
2539 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2540 xmlXPathFreeObject(hay);
2541 xmlXPathFreeObject(needle);
2542 ERROR(XPATH_INVALID_TYPE);
2543 }
2544 n = xmlStrlen(needle->stringval);
2545 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2546 valuePush(ctxt, xmlXPathNewBoolean(0));
2547 else
2548 valuePush(ctxt, xmlXPathNewBoolean(1));
2549 xmlXPathFreeObject(hay);
2550 xmlXPathFreeObject(needle);
2551}
2552
2553/**
2554 * xmlXPathSubstringFunction:
2555 * @ctxt: the XPath Parser context
2556 *
2557 * Implement the substring() XPath function
2558 * The substring function returns the substring of the first argument
2559 * starting at the position specified in the second argument with
2560 * length specified in the third argument. For example,
2561 * substring("12345",2,3) returns "234". If the third argument is not
2562 * specified, it returns the substring starting at the position specified
2563 * in the second argument and continuing to the end of the string. For
2564 * example, substring("12345",2) returns "2345". More precisely, each
2565 * character in the string (see [3.6 Strings]) is considered to have a
2566 * numeric position: the position of the first character is 1, the position
2567 * of the second character is 2 and so on. The returned substring contains
2568 * those characters for which the position of the character is greater than
2569 * or equal to the second argument and, if the third argument is specified,
2570 * less than the sum of the second and third arguments; the comparisons
2571 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2572 * - substring("12345", 1.5, 2.6) returns "234"
2573 * - substring("12345", 0, 3) returns "12"
2574 * - substring("12345", 0 div 0, 3) returns ""
2575 * - substring("12345", 1, 0 div 0) returns ""
2576 * - substring("12345", -42, 1 div 0) returns "12345"
2577 * - substring("12345", -1 div 0, 1 div 0) returns ""
2578 */
2579void
2580xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2581 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002582 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002583 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002584 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002585
2586 /*
2587 * Conformance needs to be checked !!!!!
2588 */
2589 if (nargs < 2) {
2590 CHECK_ARITY(2);
2591 }
2592 if (nargs > 3) {
2593 CHECK_ARITY(3);
2594 }
2595 if (nargs == 3) {
2596 CHECK_TYPE(XPATH_NUMBER);
2597 len = valuePop(ctxt);
2598 le = len->floatval;
2599 xmlXPathFreeObject(len);
2600 } else {
2601 le = 2000000000;
2602 }
2603 CHECK_TYPE(XPATH_NUMBER);
2604 start = valuePop(ctxt);
2605 in = start->floatval;
2606 xmlXPathFreeObject(start);
2607 CHECK_TYPE(XPATH_STRING);
2608 str = valuePop(ctxt);
2609 le += in;
2610
2611 /* integer index of the first char */
2612 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002613 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002614
2615 /* integer index of the last char */
2616 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002617 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002618
2619 /* back to a zero based len */
2620 i--;
2621 l--;
2622
2623 /* check against the string len */
2624 if (l > 1024) {
2625 l = xmlStrlen(str->stringval);
2626 }
2627 if (i < 0) {
2628 i = 0;
2629 }
2630
2631 /* number of chars to copy */
2632 l -= i;
2633
2634 ret = xmlStrsub(str->stringval, i, l);
2635 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002636 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002637 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002638 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002639 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002640 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002641 xmlXPathFreeObject(str);
2642}
2643
2644/**
2645 * xmlXPathSubstringBeforeFunction:
2646 * @ctxt: the XPath Parser context
2647 *
2648 * Implement the substring-before() XPath function
2649 * The substring-before function returns the substring of the first
2650 * argument string that precedes the first occurrence of the second
2651 * argument string in the first argument string, or the empty string
2652 * if the first argument string does not contain the second argument
2653 * string. For example, substring-before("1999/04/01","/") returns 1999.
2654 */
2655void
2656xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2657 CHECK_ARITY(2);
2658 TODO /* substring before */
2659}
2660
2661/**
2662 * xmlXPathSubstringAfterFunction:
2663 * @ctxt: the XPath Parser context
2664 *
2665 * Implement the substring-after() XPath function
2666 * The substring-after function returns the substring of the first
2667 * argument string that follows the first occurrence of the second
2668 * argument string in the first argument string, or the empty stringi
2669 * if the first argument string does not contain the second argument
2670 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2671 * and substring-after("1999/04/01","19") returns 99/04/01.
2672 */
2673void
2674xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2675 CHECK_ARITY(2);
2676 TODO /* substring after */
2677}
2678
2679/**
2680 * xmlXPathNormalizeFunction:
2681 * @ctxt: the XPath Parser context
2682 *
2683 * Implement the normalize() XPath function
2684 * The normalize function returns the argument string with white
2685 * space normalized by stripping leading and trailing whitespace
2686 * and replacing sequences of whitespace characters by a single
2687 * space. Whitespace characters are the same allowed by the S production
2688 * in XML. If the argument is omitted, it defaults to the context
2689 * node converted to a string, in other words the value of the context node.
2690 */
2691void
2692xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2693 CHECK_ARITY(1);
2694 TODO /* normalize isn't as boring as translate, but pretty much */
2695}
2696
2697/**
2698 * xmlXPathTranslateFunction:
2699 * @ctxt: the XPath Parser context
2700 *
2701 * Implement the translate() XPath function
2702 * The translate function returns the first argument string with
2703 * occurrences of characters in the second argument string replaced
2704 * by the character at the corresponding position in the third argument
2705 * string. For example, translate("bar","abc","ABC") returns the string
2706 * BAr. If there is a character in the second argument string with no
2707 * character at a corresponding position in the third argument string
2708 * (because the second argument string is longer than the third argument
2709 * string), then occurrences of that character in the first argument
2710 * string are removed. For example, translate("--aaa--","abc-","ABC")
2711 * returns "AAA". If a character occurs more than once in second
2712 * argument string, then the first occurrence determines the replacement
2713 * character. If the third argument string is longer than the second
2714 * argument string, then excess characters are ignored.
2715 */
2716void
2717xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2718 CHECK_ARITY(3);
2719 TODO /* translate is boring, waiting for UTF-8 representation too */
2720}
2721
2722/**
2723 * xmlXPathBooleanFunction:
2724 * @ctxt: the XPath Parser context
2725 *
2726 * Implement the boolean() XPath function
2727 * he boolean function converts its argument to a boolean as follows:
2728 * - a number is true if and only if it is neither positive or
2729 * negative zero nor NaN
2730 * - a node-set is true if and only if it is non-empty
2731 * - a string is true if and only if its length is non-zero
2732 */
2733void
2734xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2735 xmlXPathObjectPtr cur;
2736 int res = 0;
2737
2738 CHECK_ARITY(1);
2739 cur = valuePop(ctxt);
2740 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2741 switch (cur->type) {
2742 case XPATH_NODESET:
2743 if ((cur->nodesetval == NULL) ||
2744 (cur->nodesetval->nodeNr == 0)) res = 0;
2745 else
2746 res = 1;
2747 break;
2748 case XPATH_STRING:
2749 if ((cur->stringval == NULL) ||
2750 (cur->stringval[0] == 0)) res = 0;
2751 else
2752 res = 1;
2753 break;
2754 case XPATH_BOOLEAN:
2755 valuePush(ctxt, cur);
2756 return;
2757 case XPATH_NUMBER:
2758 if (cur->floatval) res = 1;
2759 break;
2760 default:
2761 STRANGE
2762 }
2763 xmlXPathFreeObject(cur);
2764 valuePush(ctxt, xmlXPathNewBoolean(res));
2765}
2766
2767/**
2768 * xmlXPathNotFunction:
2769 * @ctxt: the XPath Parser context
2770 *
2771 * Implement the not() XPath function
2772 * The not function returns true if its argument is false,
2773 * and false otherwise.
2774 */
2775void
2776xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2777 CHECK_ARITY(1);
2778 CHECK_TYPE(XPATH_BOOLEAN);
2779 ctxt->value->boolval = ! ctxt->value->boolval;
2780}
2781
2782/**
2783 * xmlXPathTrueFunction:
2784 * @ctxt: the XPath Parser context
2785 *
2786 * Implement the true() XPath function
2787 */
2788void
2789xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2790 CHECK_ARITY(0);
2791 valuePush(ctxt, xmlXPathNewBoolean(1));
2792}
2793
2794/**
2795 * xmlXPathFalseFunction:
2796 * @ctxt: the XPath Parser context
2797 *
2798 * Implement the false() XPath function
2799 */
2800void
2801xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2802 CHECK_ARITY(0);
2803 valuePush(ctxt, xmlXPathNewBoolean(0));
2804}
2805
2806/**
2807 * xmlXPathLangFunction:
2808 * @ctxt: the XPath Parser context
2809 *
2810 * Implement the lang() XPath function
2811 * The lang function returns true or false depending on whether the
2812 * language of the context node as specified by xml:lang attributes
2813 * is the same as or is a sublanguage of the language specified by
2814 * the argument string. The language of the context node is determined
2815 * by the value of the xml:lang attribute on the context node, or, if
2816 * the context node has no xml:lang attribute, by the value of the
2817 * xml:lang attribute on the nearest ancestor of the context node that
2818 * has an xml:lang attribute. If there is no such attribute, then lang
2819 * returns false. If there is such an attribute, then lang returns
2820 * true if the attribute value is equal to the argument ignoring case,
2821 * or if there is some suffix starting with - such that the attribute
2822 * value is equal to the argument ignoring that suffix of the attribute
2823 * value and ignoring case.
2824 */
2825void
2826xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002827 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002828 const xmlChar *theLang;
2829 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002830 int ret = 0;
2831 int i;
2832
2833 CHECK_ARITY(1);
2834 CHECK_TYPE(XPATH_STRING);
2835 val = valuePop(ctxt);
2836 lang = val->stringval;
2837 theLang = xmlNodeGetLang(ctxt->context->node);
2838 if ((theLang != NULL) && (lang != NULL)) {
2839 for (i = 0;lang[i] != 0;i++)
2840 if (toupper(lang[i]) != toupper(theLang[i]))
2841 goto not_equal;
2842 ret = 1;
2843 }
2844not_equal:
2845 xmlXPathFreeObject(val);
2846 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002847}
2848
2849/**
2850 * xmlXPathNumberFunction:
2851 * @ctxt: the XPath Parser context
2852 *
2853 * Implement the number() XPath function
2854 */
2855void
2856xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2857 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002858 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002859
2860 CHECK_ARITY(1);
2861 cur = valuePop(ctxt);
2862 switch (cur->type) {
2863 case XPATH_NODESET:
2864 valuePush(ctxt, cur);
2865 xmlXPathStringFunction(ctxt, 1);
2866 cur = valuePop(ctxt);
2867 case XPATH_STRING:
2868 res = xmlXPathStringEvalNumber(cur->stringval);
2869 valuePush(ctxt, xmlXPathNewFloat(res));
2870 xmlXPathFreeObject(cur);
2871 return;
2872 case XPATH_BOOLEAN:
2873 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2874 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2875 xmlXPathFreeObject(cur);
2876 return;
2877 case XPATH_NUMBER:
2878 valuePush(ctxt, cur);
2879 return;
2880 }
2881 STRANGE
2882}
2883
2884/**
2885 * xmlXPathSumFunction:
2886 * @ctxt: the XPath Parser context
2887 *
2888 * Implement the sum() XPath function
2889 * The sum function returns the sum of the values of the nodes in
2890 * the argument node-set.
2891 */
2892void
2893xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2894 CHECK_ARITY(1);
2895 TODO /* BUG Sum : don't understand the definition */
2896}
2897
2898/**
2899 * xmlXPathFloorFunction:
2900 * @ctxt: the XPath Parser context
2901 *
2902 * Implement the floor() XPath function
2903 * The floor function returns the largest (closest to positive infinity)
2904 * number that is not greater than the argument and that is an integer.
2905 */
2906void
2907xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2908 CHECK_ARITY(1);
2909 CHECK_TYPE(XPATH_NUMBER);
2910 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002911 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002912}
2913
2914/**
2915 * xmlXPathCeilingFunction:
2916 * @ctxt: the XPath Parser context
2917 *
2918 * Implement the ceiling() XPath function
2919 * The ceiling function returns the smallest (closest to negative infinity)
2920 * number that is not less than the argument and that is an integer.
2921 */
2922void
2923xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002924 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002925
2926 CHECK_ARITY(1);
2927 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002928 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002929 if (f != ctxt->value->floatval)
2930 ctxt->value->floatval = f + 1;
2931}
2932
2933/**
2934 * xmlXPathRoundFunction:
2935 * @ctxt: the XPath Parser context
2936 *
2937 * Implement the round() XPath function
2938 * The round function returns the number that is closest to the
2939 * argument and that is an integer. If there are two such numbers,
2940 * then the one that is even is returned.
2941 */
2942void
2943xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002944 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002945
2946 CHECK_ARITY(1);
2947 CHECK_TYPE(XPATH_NUMBER);
2948 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002949 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002950 if (ctxt->value->floatval < f + 0.5)
2951 ctxt->value->floatval = f;
2952 else if (ctxt->value->floatval == f + 0.5)
2953 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2954 else
2955 ctxt->value->floatval = f + 1;
2956}
2957
2958/************************************************************************
2959 * *
2960 * The Parser *
2961 * *
2962 ************************************************************************/
2963
2964/*
2965 * a couple of forward declarations since we use a recursive call based
2966 * implementation.
2967 */
2968void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2969void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2970void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2971void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2972
2973/**
2974 * xmlXPathParseNCName:
2975 * @ctxt: the XPath Parser context
2976 *
2977 * parse an XML namespace non qualified name.
2978 *
2979 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2980 *
2981 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2982 * CombiningChar | Extender
2983 *
2984 * Returns the namespace name or NULL
2985 */
2986
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002987xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002988xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002989 const xmlChar *q;
2990 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002991
2992 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2993 q = NEXT;
2994
2995 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2996 (CUR == '.') || (CUR == '-') ||
2997 (CUR == '_') ||
2998 (IS_COMBINING(CUR)) ||
2999 (IS_EXTENDER(CUR)))
3000 NEXT;
3001
3002 ret = xmlStrndup(q, CUR_PTR - q);
3003
3004 return(ret);
3005}
3006
3007/**
3008 * xmlXPathParseQName:
3009 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003010 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003011 *
3012 * parse an XML qualified name
3013 *
3014 * [NS 5] QName ::= (Prefix ':')? LocalPart
3015 *
3016 * [NS 6] Prefix ::= NCName
3017 *
3018 * [NS 7] LocalPart ::= NCName
3019 *
3020 * Returns the function returns the local part, and prefix is updated
3021 * to get the Prefix if any.
3022 */
3023
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003024xmlChar *
3025xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3026 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003027
3028 *prefix = NULL;
3029 ret = xmlXPathParseNCName(ctxt);
3030 if (CUR == ':') {
3031 *prefix = ret;
3032 NEXT;
3033 ret = xmlXPathParseNCName(ctxt);
3034 }
3035 return(ret);
3036}
3037
3038/**
3039 * xmlXPathStringEvalNumber:
3040 * @str: A string to scan
3041 *
3042 * [30] Number ::= Digits ('.' Digits)?
3043 * | '.' Digits
3044 * [31] Digits ::= [0-9]+
3045 *
3046 * Parse and evaluate a Number in the string
3047 *
3048 * BUG: "1.' is not valid ... James promised correction
3049 * as Digits ('.' Digits?)?
3050 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003051 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003052 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003053double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003054xmlXPathStringEvalNumber(const xmlChar *str) {
3055 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003056 double ret = 0.0;
3057 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003058 int ok = 0;
3059
3060 while (*cur == ' ') cur++;
3061 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003062 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003063 }
3064 while ((*cur >= '0') && (*cur <= '9')) {
3065 ret = ret * 10 + (*cur - '0');
3066 ok = 1;
3067 cur++;
3068 }
3069 if (*cur == '.') {
3070 cur++;
3071 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003072 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003073 }
3074 while ((*cur >= '0') && (*cur <= '9')) {
3075 mult /= 10;
3076 ret = ret + (*cur - '0') * mult;
3077 cur++;
3078 }
3079 }
3080 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003081 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003082 return(ret);
3083}
3084
3085/**
3086 * xmlXPathEvalNumber:
3087 * @ctxt: the XPath Parser context
3088 *
3089 * [30] Number ::= Digits ('.' Digits)?
3090 * | '.' Digits
3091 * [31] Digits ::= [0-9]+
3092 *
3093 * Parse and evaluate a Number, then push it on the stack
3094 *
3095 * BUG: "1.' is not valid ... James promised correction
3096 * as Digits ('.' Digits?)?
3097 */
3098void
3099xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003100 double ret = 0.0;
3101 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003102 int ok = 0;
3103
3104 CHECK_ERROR;
3105 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3106 ERROR(XPATH_NUMBER_ERROR);
3107 }
3108 while ((CUR >= '0') && (CUR <= '9')) {
3109 ret = ret * 10 + (CUR - '0');
3110 ok = 1;
3111 NEXT;
3112 }
3113 if (CUR == '.') {
3114 NEXT;
3115 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3116 ERROR(XPATH_NUMBER_ERROR);
3117 }
3118 while ((CUR >= '0') && (CUR <= '9')) {
3119 mult /= 10;
3120 ret = ret + (CUR - '0') * mult;
3121 NEXT;
3122 }
3123 }
3124 valuePush(ctxt, xmlXPathNewFloat(ret));
3125}
3126
3127/**
3128 * xmlXPathEvalLiteral:
3129 * @ctxt: the XPath Parser context
3130 *
3131 * Parse a Literal and push it on the stack.
3132 *
3133 * [29] Literal ::= '"' [^"]* '"'
3134 * | "'" [^']* "'"
3135 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003136 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003137 */
3138void
3139xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003140 const xmlChar *q;
3141 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003142
3143 if (CUR == '"') {
3144 NEXT;
3145 q = CUR_PTR;
3146 while ((IS_CHAR(CUR)) && (CUR != '"'))
3147 NEXT;
3148 if (!IS_CHAR(CUR)) {
3149 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3150 } else {
3151 ret = xmlStrndup(q, CUR_PTR - q);
3152 NEXT;
3153 }
3154 } else if (CUR == '\'') {
3155 NEXT;
3156 q = CUR_PTR;
3157 while ((IS_CHAR(CUR)) && (CUR != '\''))
3158 NEXT;
3159 if (!IS_CHAR(CUR)) {
3160 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3161 } else {
3162 ret = xmlStrndup(q, CUR_PTR - q);
3163 NEXT;
3164 }
3165 } else {
3166 ERROR(XPATH_START_LITERAL_ERROR);
3167 }
3168 if (ret == NULL) return;
3169 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003170 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003171}
3172
3173/**
3174 * xmlXPathEvalVariableReference:
3175 * @ctxt: the XPath Parser context
3176 *
3177 * Parse a VariableReference, evaluate it and push it on the stack.
3178 *
3179 * The variable bindings consist of a mapping from variable names
3180 * to variable values. The value of a variable is an object, which
3181 * of any of the types that are possible for the value of an expression,
3182 * and may also be of additional types not specified here.
3183 *
3184 * Early evaluation is possible since:
3185 * The variable bindings [...] used to evaluate a subexpression are
3186 * always the same as those used to evaluate the containing expression.
3187 *
3188 * [36] VariableReference ::= '$' QName
3189 */
3190void
3191xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003192 xmlChar *name;
3193 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003194 xmlXPathObjectPtr value;
3195
3196 if (CUR != '$') {
3197 ERROR(XPATH_VARIABLE_REF_ERROR);
3198 }
3199 name = xmlXPathParseQName(ctxt, &prefix);
3200 if (name == NULL) {
3201 ERROR(XPATH_VARIABLE_REF_ERROR);
3202 }
3203 value = xmlXPathVariablelookup(ctxt, prefix, name);
3204 if (value == NULL) {
3205 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3206 }
3207 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003208 if (prefix != NULL) xmlFree(prefix);
3209 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003210}
3211
3212
3213/**
3214 * xmlXPathFunctionLookup:
3215 * @ctxt: the XPath Parser context
3216 * @name: a name string
3217 *
3218 * Search for a function of the given name
3219 *
3220 * [35] FunctionName ::= QName - NodeType
3221 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003222 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003223 *
3224 * Returns the xmlXPathFunction if found, or NULL otherwise
3225 */
3226xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003227xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003228 switch (name[0]) {
3229 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003230 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003231 return(xmlXPathBooleanFunction);
3232 break;
3233 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003234 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003235 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003236 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003237 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003238 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003239 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003240 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003241 return(xmlXPathContainsFunction);
3242 break;
3243 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003244 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003245 return(xmlXPathIdFunction);
3246 break;
3247 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003248 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003249 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003250 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003251 return(xmlXPathFloorFunction);
3252 break;
3253 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003254 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003255 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003256 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003257 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003258 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003259 return(xmlXPathLocalPartFunction);
3260 break;
3261 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003262 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003263 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003264 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003265 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003266 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003267 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003268 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3269 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003270 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003271 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003272 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003273 return(xmlXPathNumberFunction);
3274 break;
3275 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003276 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003277 return(xmlXPathPositionFunction);
3278 break;
3279 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003280 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003281 return(xmlXPathRoundFunction);
3282 break;
3283 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003284 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003285 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003286 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003287 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003288 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003289 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003290 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003291 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003292 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003293 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003294 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003295 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003296 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003297 return(xmlXPathSumFunction);
3298 break;
3299 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003300 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003301 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003302 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003303 return(xmlXPathTranslateFunction);
3304 break;
3305 }
3306 return(NULL);
3307}
3308
3309/**
3310 * xmlXPathEvalLocationPathName:
3311 * @ctxt: the XPath Parser context
3312 * @name: a name string
3313 *
3314 * Various names in the beginning of a LocationPath expression
3315 * indicate whether that's an Axis, a node type,
3316 *
3317 * [6] AxisName ::= 'ancestor'
3318 * | 'ancestor-or-self'
3319 * | 'attribute'
3320 * | 'child'
3321 * | 'descendant'
3322 * | 'descendant-or-self'
3323 * | 'following'
3324 * | 'following-sibling'
3325 * | 'namespace'
3326 * | 'parent'
3327 * | 'preceding'
3328 * | 'preceding-sibling'
3329 * | 'self'
3330 * [38] NodeType ::= 'comment'
3331 * | 'text'
3332 * | 'processing-instruction'
3333 * | 'node'
3334 */
3335int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003336xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003337 switch (name[0]) {
3338 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003339 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3340 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3341 return(AXIS_ANCESTOR_OR_SELF);
3342 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003343 break;
3344 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003345 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3346 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003347 break;
3348 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003349 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3350 return(AXIS_DESCENDANT);
3351 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3352 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003353 break;
3354 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003355 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3356 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3357 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003358 break;
3359 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003360 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3361 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003362 break;
3363 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003364 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3365 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3366 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3367 return(AXIS_PRECEDING_SIBLING);
3368 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3369 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003370 break;
3371 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003372 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003373 break;
3374 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003375 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003376 break;
3377 }
3378 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3379 return(0);
3380}
3381
3382/**
3383 * xmlXPathEvalFunctionCall:
3384 * @ctxt: the XPath Parser context
3385 *
3386 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3387 * [17] Argument ::= Expr
3388 *
3389 * Parse and evaluate a function call, the evaluation of all arguments are
3390 * pushed on the stack
3391 */
3392void
3393xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003394 xmlChar *name;
3395 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003396 xmlXPathFunction func;
3397 int nbargs = 0;
3398
3399 name = xmlXPathParseQName(ctxt, &prefix);
3400 if (name == NULL) {
3401 ERROR(XPATH_EXPR_ERROR);
3402 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003403 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003404 func = xmlXPathIsFunction(ctxt, name);
3405 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003406 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003407 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3408 }
3409#ifdef DEBUG_EXPR
3410 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3411#endif
3412
3413 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003414 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003415 ERROR(XPATH_EXPR_ERROR);
3416 }
3417 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003418 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003419
3420 while (CUR != ')') {
3421 xmlXPathEvalExpr(ctxt);
3422 nbargs++;
3423 if (CUR == ')') break;
3424 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003425 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003426 ERROR(XPATH_EXPR_ERROR);
3427 }
3428 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003429 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003430 }
3431 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003432 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003433 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003434 func(ctxt, nbargs);
3435}
3436
3437/**
3438 * xmlXPathEvalPrimaryExpr:
3439 * @ctxt: the XPath Parser context
3440 *
3441 * [15] PrimaryExpr ::= VariableReference
3442 * | '(' Expr ')'
3443 * | Literal
3444 * | Number
3445 * | FunctionCall
3446 *
3447 * Parse and evaluate a primary expression, then push the result on the stack
3448 */
3449void
3450xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003451 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003452 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3453 else if (CUR == '(') {
3454 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003455 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003456 xmlXPathEvalExpr(ctxt);
3457 if (CUR != ')') {
3458 ERROR(XPATH_EXPR_ERROR);
3459 }
3460 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003461 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003462 } else if (IS_DIGIT(CUR)) {
3463 xmlXPathEvalNumber(ctxt);
3464 } else if ((CUR == '\'') || (CUR == '"')) {
3465 xmlXPathEvalLiteral(ctxt);
3466 } else {
3467 xmlXPathEvalFunctionCall(ctxt);
3468 }
3469}
3470
3471/**
3472 * xmlXPathEvalFilterExpr:
3473 * @ctxt: the XPath Parser context
3474 *
3475 * [20] FilterExpr ::= PrimaryExpr
3476 * | FilterExpr Predicate
3477 *
3478 * Parse and evaluate a filter expression, then push the result on the stack
3479 * Square brackets are used to filter expressions in the same way that
3480 * they are used in location paths. It is an error if the expression to
3481 * be filtered does not evaluate to a node-set. The context node list
3482 * used for evaluating the expression in square brackets is the node-set
3483 * to be filtered listed in document order.
3484 */
3485
3486void
3487xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3488 /****
3489 xmlNodeSetPtr oldset = NULL;
3490 xmlXPathObjectPtr arg;
3491 ****/
3492
3493 xmlXPathEvalPrimaryExpr(ctxt);
3494 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003495 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003496
3497 if (CUR != '[') return;
3498
3499 CHECK_TYPE(XPATH_NODESET);
3500
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003501 while (CUR == '[') {
3502 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003503 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003504 }
3505
3506
3507}
3508
3509/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003510 * xmlXPathScanName:
3511 * @ctxt: the XPath Parser context
3512 *
3513 * Trickery: parse an XML name but without consuming the input flow
3514 * Needed for rollback cases.
3515 *
3516 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3517 * CombiningChar | Extender
3518 *
3519 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3520 *
3521 * [6] Names ::= Name (S Name)*
3522 *
3523 * Returns the Name parsed or NULL
3524 */
3525
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003526xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003527xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003528 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003529 int len = 0;
3530
Daniel Veillard00fdf371999-10-08 09:40:39 +00003531 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003532 if (!IS_LETTER(CUR) && (CUR != '_') &&
3533 (CUR != ':')) {
3534 return(NULL);
3535 }
3536
3537 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3538 (NXT(len) == '.') || (NXT(len) == '-') ||
3539 (NXT(len) == '_') || (NXT(len) == ':') ||
3540 (IS_COMBINING(NXT(len))) ||
3541 (IS_EXTENDER(NXT(len)))) {
3542 buf[len] = NXT(len);
3543 len++;
3544 if (len >= XML_MAX_NAMELEN) {
3545 fprintf(stderr,
3546 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3547 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3548 (NXT(len) == '.') || (NXT(len) == '-') ||
3549 (NXT(len) == '_') || (NXT(len) == ':') ||
3550 (IS_COMBINING(NXT(len))) ||
3551 (IS_EXTENDER(NXT(len))))
3552 len++;
3553 break;
3554 }
3555 }
3556 return(xmlStrndup(buf, len));
3557}
3558
3559/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003560 * xmlXPathEvalPathExpr:
3561 * @ctxt: the XPath Parser context
3562 *
3563 * [19] PathExpr ::= LocationPath
3564 * | FilterExpr
3565 * | FilterExpr '/' RelativeLocationPath
3566 * | FilterExpr '//' RelativeLocationPath
3567 *
3568 * Parse and evaluate a path expression, then push the result on the stack
3569 * The / operator and // operators combine an arbitrary expression
3570 * and a relative location path. It is an error if the expression
3571 * does not evaluate to a node-set.
3572 * The / operator does composition in the same way as when / is
3573 * used in a location path. As in location paths, // is short for
3574 * /descendant-or-self::node()/.
3575 */
3576
3577void
3578xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3579 xmlNodeSetPtr newset = NULL;
3580
Daniel Veillard00fdf371999-10-08 09:40:39 +00003581 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003582 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3583 (CUR == '\'') || (CUR == '"')) {
3584 xmlXPathEvalFilterExpr(ctxt);
3585 CHECK_ERROR;
3586 if ((CUR == '/') && (NXT(1) == '/')) {
3587 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003588 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003589 if (ctxt->context->nodelist == NULL) {
3590 STRANGE
3591 xmlXPathRoot(ctxt);
3592 }
3593 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3594 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3595 if (ctxt->context->nodelist != NULL)
3596 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3597 ctxt->context->nodelist = newset;
3598 ctxt->context->node = NULL;
3599 xmlXPathEvalRelativeLocationPath(ctxt);
3600 } else if (CUR == '/') {
3601 xmlXPathEvalRelativeLocationPath(ctxt);
3602 }
3603 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003604 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003605 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003606
3607 name = xmlXPathScanName(ctxt);
3608 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3609 xmlXPathEvalLocationPath(ctxt);
3610 else
3611 xmlXPathEvalFilterExpr(ctxt);
3612 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003613 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003614 }
3615}
3616
3617/**
3618 * xmlXPathEvalUnionExpr:
3619 * @ctxt: the XPath Parser context
3620 *
3621 * [18] UnionExpr ::= PathExpr
3622 * | UnionExpr '|' PathExpr
3623 *
3624 * Parse and evaluate an union expression, then push the result on the stack
3625 */
3626
3627void
3628xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3629 xmlXPathEvalPathExpr(ctxt);
3630 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003631 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003632 if (CUR == '|') {
3633 xmlNodeSetPtr old = ctxt->context->nodelist;
3634
Daniel Veillard00fdf371999-10-08 09:40:39 +00003635 NEXT;
3636 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003637 xmlXPathEvalPathExpr(ctxt);
3638
3639 if (ctxt->context->nodelist == NULL)
3640 ctxt->context->nodelist = old;
3641 else {
3642 ctxt->context->nodelist =
3643 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3644 xmlXPathFreeNodeSet(old);
3645 }
3646 }
3647}
3648
3649/**
3650 * xmlXPathEvalUnaryExpr:
3651 * @ctxt: the XPath Parser context
3652 *
3653 * [27] UnaryExpr ::= UnionExpr
3654 * | '-' UnaryExpr
3655 *
3656 * Parse and evaluate an unary expression, then push the result on the stack
3657 */
3658
3659void
3660xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3661 int minus = 0;
3662
Daniel Veillard00fdf371999-10-08 09:40:39 +00003663 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003664 if (CUR == '-') {
3665 minus = 1;
3666 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003667 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003668 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003669 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003670 CHECK_ERROR;
3671 if (minus) {
3672 xmlXPathValueFlipSign(ctxt);
3673 }
3674}
3675
3676/**
3677 * xmlXPathEvalMultiplicativeExpr:
3678 * @ctxt: the XPath Parser context
3679 *
3680 * [26] MultiplicativeExpr ::= UnaryExpr
3681 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3682 * | MultiplicativeExpr 'div' UnaryExpr
3683 * | MultiplicativeExpr 'mod' UnaryExpr
3684 * [34] MultiplyOperator ::= '*'
3685 *
3686 * Parse and evaluate an Additive expression, then push the result on the stack
3687 */
3688
3689void
3690xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3691 xmlXPathEvalUnaryExpr(ctxt);
3692 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003693 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003694 while ((CUR == '*') ||
3695 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3696 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3697 int op = -1;
3698
3699 if (CUR == '*') {
3700 op = 0;
3701 NEXT;
3702 } else if (CUR == 'd') {
3703 op = 1;
3704 SKIP(3);
3705 } else if (CUR == 'm') {
3706 op = 2;
3707 SKIP(3);
3708 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003709 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003710 xmlXPathEvalUnaryExpr(ctxt);
3711 CHECK_ERROR;
3712 switch (op) {
3713 case 0:
3714 xmlXPathMultValues(ctxt);
3715 break;
3716 case 1:
3717 xmlXPathDivValues(ctxt);
3718 break;
3719 case 2:
3720 xmlXPathModValues(ctxt);
3721 break;
3722 }
3723 }
3724}
3725
3726/**
3727 * xmlXPathEvalAdditiveExpr:
3728 * @ctxt: the XPath Parser context
3729 *
3730 * [25] AdditiveExpr ::= MultiplicativeExpr
3731 * | AdditiveExpr '+' MultiplicativeExpr
3732 * | AdditiveExpr '-' MultiplicativeExpr
3733 *
3734 * Parse and evaluate an Additive expression, then push the result on the stack
3735 */
3736
3737void
3738xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3739 xmlXPathEvalMultiplicativeExpr(ctxt);
3740 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003741 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003742 while ((CUR == '+') || (CUR == '-')) {
3743 int plus;
3744
3745 if (CUR == '+') plus = 1;
3746 else plus = 0;
3747 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003748 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003749 xmlXPathEvalMultiplicativeExpr(ctxt);
3750 CHECK_ERROR;
3751 if (plus) xmlXPathAddValues(ctxt);
3752 else xmlXPathSubValues(ctxt);
3753 }
3754}
3755
3756/**
3757 * xmlXPathEvalRelationalExpr:
3758 * @ctxt: the XPath Parser context
3759 *
3760 * [24] RelationalExpr ::= AdditiveExpr
3761 * | RelationalExpr '<' AdditiveExpr
3762 * | RelationalExpr '>' AdditiveExpr
3763 * | RelationalExpr '<=' AdditiveExpr
3764 * | RelationalExpr '>=' AdditiveExpr
3765 *
3766 * A <= B > C is allowed ? Answer from James, yes with
3767 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3768 * which is basically what got implemented.
3769 *
3770 * Parse and evaluate a Relational expression, then push the result
3771 * on the stack
3772 */
3773
3774void
3775xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3776 xmlXPathEvalAdditiveExpr(ctxt);
3777 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003778 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003779 while ((CUR == '<') ||
3780 (CUR == '>') ||
3781 ((CUR == '<') && (NXT(1) == '=')) ||
3782 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003783 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003784
3785 if (CUR == '<') inf = 1;
3786 else inf = 0;
3787 if (NXT(1) == '=') strict = 0;
3788 else strict = 1;
3789 NEXT;
3790 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003791 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003792 xmlXPathEvalAdditiveExpr(ctxt);
3793 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003794 ret = xmlXPathCompareValues(ctxt, inf, strict);
3795 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003796 }
3797}
3798
3799/**
3800 * xmlXPathEvalEqualityExpr:
3801 * @ctxt: the XPath Parser context
3802 *
3803 * [23] EqualityExpr ::= RelationalExpr
3804 * | EqualityExpr '=' RelationalExpr
3805 * | EqualityExpr '!=' RelationalExpr
3806 *
3807 * A != B != C is allowed ? Answer from James, yes with
3808 * (RelationalExpr = RelationalExpr) = RelationalExpr
3809 * (RelationalExpr != RelationalExpr) != RelationalExpr
3810 * which is basically what got implemented.
3811 *
3812 * Parse and evaluate an Equality expression, then push the result on the stack
3813 *
3814 */
3815void
3816xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3817 xmlXPathEvalRelationalExpr(ctxt);
3818 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003819 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003820 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003821 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003822 int eq, equal;
3823
3824 if (CUR == '=') eq = 1;
3825 else eq = 0;
3826 NEXT;
3827 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003828 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003829 xmlXPathEvalRelationalExpr(ctxt);
3830 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003831 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003832 if (eq) res = xmlXPathNewBoolean(equal);
3833 else res = xmlXPathNewBoolean(!equal);
3834 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003835 }
3836}
3837
3838/**
3839 * xmlXPathEvalAndExpr:
3840 * @ctxt: the XPath Parser context
3841 *
3842 * [22] AndExpr ::= EqualityExpr
3843 * | AndExpr 'and' EqualityExpr
3844 *
3845 * Parse and evaluate an AND expression, then push the result on the stack
3846 *
3847 */
3848void
3849xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3850 xmlXPathEvalEqualityExpr(ctxt);
3851 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003852 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003853 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3854 xmlXPathObjectPtr arg1, arg2;
3855
3856 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003857 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003858 xmlXPathEvalEqualityExpr(ctxt);
3859 CHECK_ERROR;
3860 arg2 = valuePop(ctxt);
3861 arg1 = valuePop(ctxt);
3862 arg1->boolval &= arg2->boolval;
3863 valuePush(ctxt, arg1);
3864 xmlXPathFreeObject(arg2);
3865 }
3866}
3867
3868/**
3869 * xmlXPathEvalExpr:
3870 * @ctxt: the XPath Parser context
3871 *
3872 * [14] Expr ::= OrExpr
3873 * [21] OrExpr ::= AndExpr
3874 * | OrExpr 'or' AndExpr
3875 *
3876 * Parse and evaluate an expression, then push the result on the stack
3877 *
3878 */
3879void
3880xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3881 xmlXPathEvalAndExpr(ctxt);
3882 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003883 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003884 while ((CUR == 'o') && (NXT(1) == 'r')) {
3885 xmlXPathObjectPtr arg1, arg2;
3886
3887 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003888 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003889 xmlXPathEvalAndExpr(ctxt);
3890 CHECK_ERROR;
3891 arg2 = valuePop(ctxt);
3892 arg1 = valuePop(ctxt);
3893 arg1->boolval |= arg2->boolval;
3894 valuePush(ctxt, arg1);
3895 xmlXPathFreeObject(arg2);
3896 }
3897}
3898
3899/**
3900 * xmlXPathEvaluatePredicateResult:
3901 * @ctxt: the XPath Parser context
3902 * @res: the Predicate Expression evaluation result
3903 * @index: index of the current node in the current list
3904 *
3905 * Evaluate a predicate result for the current node.
3906 * A PredicateExpr is evaluated by evaluating the Expr and converting
3907 * the result to a boolean. If the result is a number, the result will
3908 * be converted to true if the number is equal to the position of the
3909 * context node in the context node list (as returned by the position
3910 * function) and will be converted to false otherwise; if the result
3911 * is not a number, then the result will be converted as if by a call
3912 * to the boolean function.
3913 */
3914int
3915xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3916 xmlXPathObjectPtr res, int index) {
3917 if (res == NULL) return(0);
3918 switch (res->type) {
3919 case XPATH_BOOLEAN:
3920 return(res->boolval);
3921 case XPATH_NUMBER:
3922 return(res->floatval == index);
3923 case XPATH_NODESET:
3924 return(res->nodesetval->nodeNr != 0);
3925 case XPATH_STRING:
3926 return((res->stringval != NULL) &&
3927 (xmlStrlen(res->stringval) != 0));
3928 default:
3929 STRANGE
3930 }
3931 return(0);
3932}
3933
3934/**
3935 * xmlXPathEvalPredicate:
3936 * @ctxt: the XPath Parser context
3937 *
3938 * [8] Predicate ::= '[' PredicateExpr ']'
3939 * [9] PredicateExpr ::= Expr
3940 *
3941 * Parse and evaluate a predicate for all the elements of the
3942 * current node list. Then refine the list by removing all
3943 * nodes where the predicate is false.
3944 */
3945void
3946xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003947 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003948 xmlXPathObjectPtr res;
3949 xmlNodeSetPtr newset = NULL;
3950 int i;
3951
Daniel Veillard00fdf371999-10-08 09:40:39 +00003952 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003953 if (CUR != '[') {
3954 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3955 }
3956 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003957 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003958 if ((ctxt->context->nodelist == NULL) ||
3959 (ctxt->context->nodelist->nodeNr == 0)) {
3960 ctxt->context->node = NULL;
3961 xmlXPathEvalExpr(ctxt);
3962 CHECK_ERROR;
3963 res = valuePop(ctxt);
3964 if (res != NULL)
3965 xmlXPathFreeObject(res);
3966 } else {
3967 cur = ctxt->cur;
3968 newset = xmlXPathNodeSetCreate(NULL);
3969 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3970 ctxt->cur = cur;
3971 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3972 xmlXPathEvalExpr(ctxt);
3973 CHECK_ERROR;
3974 res = valuePop(ctxt);
3975 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3976 xmlXPathNodeSetAdd(newset,
3977 ctxt->context->nodelist->nodeTab[i]);
3978 if (res != NULL)
3979 xmlXPathFreeObject(res);
3980 }
3981 if (ctxt->context->nodelist != NULL)
3982 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3983 ctxt->context->nodelist = newset;
3984 ctxt->context->node = NULL;
3985 }
3986 if (CUR != ']') {
3987 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3988 }
3989 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003990 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003991#ifdef DEBUG_STEP
3992 fprintf(xmlXPathDebug, "After predicate : ");
3993 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3994#endif
3995}
3996
3997/**
3998 * xmlXPathEvalBasis:
3999 * @ctxt: the XPath Parser context
4000 *
4001 * [5] Basis ::= AxisName '::' NodeTest
4002 * | AbbreviatedBasis
4003 * [13] AbbreviatedBasis ::= NodeTest
4004 * | '@' NodeTest
4005 * [7] NodeTest ::= WildcardName
4006 * | NodeType '(' ')'
4007 * | 'processing-instruction' '(' Literal ')'
4008 * [37] WildcardName ::= '*'
4009 * | NCName ':' '*'
4010 * | QName
4011 *
4012 * Evaluate one step in a Location Path
4013 */
4014void
4015xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004016 xmlChar *name = NULL;
4017 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004018 int type = 0;
4019 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4020 int nodetest = NODE_TEST_NONE;
4021 int nodetype = 0;
4022 xmlNodeSetPtr newset = NULL;
4023
4024 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004025 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004026 axis = AXIS_ATTRIBUTE;
4027 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004028 } else if (CUR == '*') {
4029 NEXT;
4030 nodetest = NODE_TEST_ALL;
4031 } else {
4032 name = xmlXPathParseNCName(ctxt);
4033 if (name == NULL) {
4034 ERROR(XPATH_EXPR_ERROR);
4035 }
4036 type = xmlXPathGetNameType(ctxt, name);
4037 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004038 case IS_FUNCTION: {
4039 xmlXPathFunction func;
4040 int nbargs = 0;
4041 xmlXPathObjectPtr top;
4042
4043 top = ctxt->value;
4044 func = xmlXPathIsFunction(ctxt, name);
4045 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004046 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004047 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4048 }
4049#ifdef DEBUG_EXPR
4050 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4051#endif
4052
4053 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004054 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004055 ERROR(XPATH_EXPR_ERROR);
4056 }
4057 NEXT;
4058
4059 while (CUR != ')') {
4060 xmlXPathEvalExpr(ctxt);
4061 nbargs++;
4062 if (CUR == ')') break;
4063 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004064 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004065 ERROR(XPATH_EXPR_ERROR);
4066 }
4067 NEXT;
4068 }
4069 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004070 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004071 func(ctxt, nbargs);
4072 if ((ctxt->value != top) &&
4073 (ctxt->value != NULL) &&
4074 (ctxt->value->type == XPATH_NODESET)) {
4075 xmlXPathObjectPtr cur;
4076
4077 cur = valuePop(ctxt);
4078 ctxt->context->nodelist = cur->nodesetval;
4079 ctxt->context->node = NULL;
4080 cur->nodesetval = NULL;
4081 xmlXPathFreeObject(cur);
4082 }
4083 return;
4084 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004085 /*
4086 * Simple case: no axis seach all given node types.
4087 */
4088 case NODE_TYPE_COMMENT:
4089 if ((CUR != '(') || (NXT(1) != ')')) break;
4090 SKIP(2);
4091 nodetest = NODE_TEST_TYPE;
4092 nodetype = XML_COMMENT_NODE;
4093 goto search_nodes;
4094 case NODE_TYPE_TEXT:
4095 if ((CUR != '(') || (NXT(1) != ')')) break;
4096 SKIP(2);
4097 nodetest = NODE_TEST_TYPE;
4098 nodetype = XML_TEXT_NODE;
4099 goto search_nodes;
4100 case NODE_TYPE_NODE:
4101 if ((CUR != '(') || (NXT(1) != ')')) {
4102 nodetest = NODE_TEST_NAME;
4103 break;
4104 }
4105 SKIP(2);
4106 nodetest = NODE_TEST_TYPE;
4107 nodetype = XML_ELEMENT_NODE;
4108 goto search_nodes;
4109 case NODE_TYPE_PI:
4110 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004111 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004112 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004113 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004114 xmlXPathObjectPtr cur;
4115
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004116 /*
4117 * Specific case: search a PI by name.
4118 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004119 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004120 nodetest = NODE_TEST_PI;
4121 xmlXPathEvalLiteral(ctxt);
4122 CHECK_ERROR;
4123 if (CUR != ')')
4124 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004125 NEXT;
4126 xmlXPathStringFunction(ctxt, 1);
4127 CHECK_ERROR;
4128 cur = valuePop(ctxt);
4129 name = xmlStrdup(cur->stringval);
4130 xmlXPathFreeObject(cur);
4131 } else
4132 SKIP(2);
4133 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004134 goto search_nodes;
4135
4136 /*
4137 * Handling of the compund form: got the axis.
4138 */
4139 case AXIS_ANCESTOR:
4140 case AXIS_ANCESTOR_OR_SELF:
4141 case AXIS_ATTRIBUTE:
4142 case AXIS_CHILD:
4143 case AXIS_DESCENDANT:
4144 case AXIS_DESCENDANT_OR_SELF:
4145 case AXIS_FOLLOWING:
4146 case AXIS_FOLLOWING_SIBLING:
4147 case AXIS_NAMESPACE:
4148 case AXIS_PARENT:
4149 case AXIS_PRECEDING:
4150 case AXIS_PRECEDING_SIBLING:
4151 case AXIS_SELF:
4152 if ((CUR != ':') || (NXT(1) != ':')) {
4153 nodetest = NODE_TEST_NAME;
4154 break;
4155 }
4156 SKIP(2);
4157 axis = type;
4158 break;
4159
4160 /*
4161 * Default: abbreviated syntax the axis is AXIS_CHILD
4162 */
4163 default:
4164 nodetest = NODE_TEST_NAME;
4165 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004166parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004167 if (nodetest == NODE_TEST_NONE) {
4168 if (CUR == '*') {
4169 NEXT;
4170 nodetest = NODE_TEST_ALL;
4171 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004172 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004173 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004174 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004175 if (name == NULL) {
4176 ERROR(XPATH_EXPR_ERROR);
4177 }
4178 type = xmlXPathGetNameType(ctxt, name);
4179 switch (type) {
4180 /*
4181 * Simple case: no axis seach all given node types.
4182 */
4183 case NODE_TYPE_COMMENT:
4184 if ((CUR != '(') || (NXT(1) != ')')) break;
4185 SKIP(2);
4186 nodetest = NODE_TEST_TYPE;
4187 nodetype = XML_COMMENT_NODE;
4188 goto search_nodes;
4189 case NODE_TYPE_TEXT:
4190 if ((CUR != '(') || (NXT(1) != ')')) break;
4191 SKIP(2);
4192 nodetest = NODE_TEST_TYPE;
4193 nodetype = XML_TEXT_NODE;
4194 goto search_nodes;
4195 case NODE_TYPE_NODE:
4196 if ((CUR != '(') || (NXT(1) != ')')) {
4197 nodetest = NODE_TEST_NAME;
4198 break;
4199 }
4200 SKIP(2);
4201 nodetest = NODE_TEST_TYPE;
4202 nodetype = XML_ELEMENT_NODE;
4203 goto search_nodes;
4204 case NODE_TYPE_PI:
4205 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004206 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004207 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004208 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004209 xmlXPathObjectPtr cur;
4210
Daniel Veillardb05deb71999-08-10 19:04:08 +00004211 /*
4212 * Specific case: search a PI by name.
4213 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004214 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004215 nodetest = NODE_TEST_PI;
4216 xmlXPathEvalLiteral(ctxt);
4217 CHECK_ERROR;
4218 if (CUR != ')')
4219 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004220 NEXT;
4221 xmlXPathStringFunction(ctxt, 1);
4222 CHECK_ERROR;
4223 cur = valuePop(ctxt);
4224 name = xmlStrdup(cur->stringval);
4225 xmlXPathFreeObject(cur);
4226 } else
4227 SKIP(2);
4228 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004229 goto search_nodes;
4230 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004231 nodetest = NODE_TEST_NAME;
4232 }
4233 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4234 NEXT;
4235 prefix = name;
4236 if (CUR == '*') {
4237 NEXT;
4238 nodetest = NODE_TEST_ALL;
4239 } else
4240 name = xmlXPathParseNCName(ctxt);
4241 } else if (name == NULL)
4242 ERROR(XPATH_EXPR_ERROR);
4243 }
4244
4245search_nodes:
4246
4247#ifdef DEBUG_STEP
4248 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4249#endif
4250 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4251 prefix, name);
4252 if (ctxt->context->nodelist != NULL)
4253 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4254 ctxt->context->nodelist = newset;
4255 ctxt->context->node = NULL;
4256#ifdef DEBUG_STEP
4257 fprintf(xmlXPathDebug, "Basis : ");
4258 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4259#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004260 if (name != NULL) xmlFree(name);
4261 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004262}
4263
4264/**
4265 * xmlXPathEvalStep:
4266 * @ctxt: the XPath Parser context
4267 *
4268 * [4] Step ::= Basis Predicate*
4269 * | AbbreviatedStep
4270 * [12] AbbreviatedStep ::= '.'
4271 * | '..'
4272 *
4273 * Evaluate one step in a Location Path
4274 * A location step of . is short for self::node(). This is
4275 * particularly useful in conjunction with //. For example, the
4276 * location path .//para is short for
4277 * self::node()/descendant-or-self::node()/child::para
4278 * and so will select all para descendant elements of the context
4279 * node.
4280 * Similarly, a location step of .. is short for parent::node().
4281 * For example, ../title is short for parent::node()/child::title
4282 * and so will select the title children of the parent of the context
4283 * node.
4284 */
4285void
4286xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4287 xmlNodeSetPtr newset = NULL;
4288
Daniel Veillard00fdf371999-10-08 09:40:39 +00004289 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004290 if ((CUR == '.') && (NXT(1) == '.')) {
4291 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004292 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004293 if (ctxt->context->nodelist == NULL) {
4294 STRANGE
4295 xmlXPathRoot(ctxt);
4296 }
4297 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4298 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4299 if (ctxt->context->nodelist != NULL)
4300 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4301 ctxt->context->nodelist = newset;
4302 ctxt->context->node = NULL;
4303 } else if (CUR == '.') {
4304 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004305 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004306 } else {
4307 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004308 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004309 while (CUR == '[') {
4310 xmlXPathEvalPredicate(ctxt);
4311 }
4312 }
4313#ifdef DEBUG_STEP
4314 fprintf(xmlXPathDebug, "Step : ");
4315 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4316#endif
4317}
4318
4319/**
4320 * xmlXPathEvalRelativeLocationPath:
4321 * @ctxt: the XPath Parser context
4322 *
4323 * [3] RelativeLocationPath ::= Step
4324 * | RelativeLocationPath '/' Step
4325 * | AbbreviatedRelativeLocationPath
4326 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4327 *
4328 */
4329void
4330xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4331 xmlNodeSetPtr newset = NULL;
4332
Daniel Veillard00fdf371999-10-08 09:40:39 +00004333 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004334 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004335 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004336 while (CUR == '/') {
4337 if ((CUR == '/') && (NXT(1) == '/')) {
4338 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004339 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004340 if (ctxt->context->nodelist == NULL) {
4341 STRANGE
4342 xmlXPathRoot(ctxt);
4343 }
4344 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4345 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4346 if (ctxt->context->nodelist != NULL)
4347 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4348 ctxt->context->nodelist = newset;
4349 ctxt->context->node = NULL;
4350 xmlXPathEvalStep(ctxt);
4351 } else if (CUR == '/') {
4352 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004353 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004354 xmlXPathEvalStep(ctxt);
4355 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004356 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004357 }
4358}
4359
4360/**
4361 * xmlXPathEvalLocationPath:
4362 * @ctxt: the XPath Parser context
4363 *
4364 * [1] LocationPath ::= RelativeLocationPath
4365 * | AbsoluteLocationPath
4366 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4367 * | AbbreviatedAbsoluteLocationPath
4368 * [10] AbbreviatedAbsoluteLocationPath ::=
4369 * '//' RelativeLocationPath
4370 *
4371 * // is short for /descendant-or-self::node()/. For example,
4372 * //para is short for /descendant-or-self::node()/child::para and
4373 * so will select any para element in the document (even a para element
4374 * that is a document element will be selected by //para since the
4375 * document element node is a child of the root node); div//para is
4376 * short for div/descendant-or-self::node()/child::para and so will
4377 * select all para descendants of div children.
4378 */
4379void
4380xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4381 xmlNodeSetPtr newset = NULL;
4382
Daniel Veillard00fdf371999-10-08 09:40:39 +00004383 SKIP_BLANKS;
4384 if (CUR != '/') {
4385 xmlXPathEvalRelativeLocationPath(ctxt);
4386 } else {
4387 while (CUR == '/') {
4388 if ((CUR == '/') && (NXT(1) == '/')) {
4389 SKIP(2);
4390 SKIP_BLANKS;
4391 if (ctxt->context->nodelist == NULL)
4392 xmlXPathRoot(ctxt);
4393 newset = xmlXPathNodeCollectAndTest(ctxt,
4394 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4395 XML_ELEMENT_NODE, NULL, NULL);
4396 if (ctxt->context->nodelist != NULL)
4397 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4398 ctxt->context->nodelist = newset;
4399 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004400 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004401 } else if (CUR == '/') {
4402 NEXT;
4403 SKIP_BLANKS;
4404 xmlXPathRoot(ctxt);
4405 if (CUR != 0)
4406 xmlXPathEvalRelativeLocationPath(ctxt);
4407 } else {
4408 xmlXPathEvalRelativeLocationPath(ctxt);
4409 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004410 }
4411 }
4412}
4413
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004414/**
4415 * xmlXPathEval:
4416 * @str: the XPath expression
4417 * @ctxt: the XPath context
4418 *
4419 * Evaluate the XPath Location Path in the given context.
4420 *
4421 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4422 * the caller has to free the object.
4423 */
4424xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004425xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004426 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004427 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004428 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004429
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004430 xmlXPathInit();
4431
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004432 CHECK_CONTEXT
4433
4434 if (xmlXPathDebug == NULL)
4435 xmlXPathDebug = stderr;
4436 pctxt = xmlXPathNewParserContext(str, ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004437 if (str[0] == '/')
4438 xmlXPathRoot(pctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004439 xmlXPathEvalLocationPath(pctxt);
4440
Daniel Veillardb96e6431999-08-29 21:02:19 +00004441 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004442 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004443 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004444 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004445 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004446 stack++;
4447 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004448 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004449 if (stack != 0) {
4450 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4451 stack);
4452 }
4453 if (pctxt->error == XPATH_EXPRESSION_OK)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004454 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004455 else
4456 res = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004457 xmlXPathFreeParserContext(pctxt);
4458 return(res);
4459}
4460
4461/**
4462 * xmlXPathEvalExpression:
4463 * @str: the XPath expression
4464 * @ctxt: the XPath context
4465 *
4466 * Evaluate the XPath expression in the given context.
4467 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004468 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004469 * the caller has to free the object.
4470 */
4471xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004472xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004473 xmlXPathParserContextPtr pctxt;
4474 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004475 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004476
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004477 xmlXPathInit();
4478
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004479 CHECK_CONTEXT
4480
4481 if (xmlXPathDebug == NULL)
4482 xmlXPathDebug = stderr;
4483 pctxt = xmlXPathNewParserContext(str, ctxt);
4484 xmlXPathEvalExpr(pctxt);
4485
4486 res = valuePop(pctxt);
4487 do {
4488 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004489 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004490 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004491 stack++;
4492 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004493 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004494 if (stack != 0) {
4495 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4496 stack);
4497 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004498 xmlXPathFreeParserContext(pctxt);
4499 return(res);
4500}
4501