blob: 4882b04f107d2e83a7b6bfbfdf5964bf4dfa4185 [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 Veillard1566d3a1999-07-15 14:24:29 +0000189 exit(1); \
190 } \
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#ifdef DEBUG_EXPR
1222 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
1223 arg1->stringval, arg2->stringval);
1224#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001225 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001226 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001227 xmlXPathFreeObject(arg1);
1228 xmlXPathFreeObject(arg2);
1229 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001230}
1231
1232/**
1233 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001234 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001235 * @inf: less than (1) or greater than (2)
1236 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001237 *
1238 * Implement the compare operation on XPath objects:
1239 * @arg1 < @arg2 (1, 1, ...
1240 * @arg1 <= @arg2 (1, 0, ...
1241 * @arg1 > @arg2 (0, 1, ...
1242 * @arg1 >= @arg2 (0, 0, ...
1243 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001244 * When neither object to be compared is a node-set and the operator is
1245 * <=, <, >=, >, then the objects are compared by converted both objects
1246 * to numbers and comparing the numbers according to IEEE 754. The <
1247 * comparison will be true if and only if the first number is less than the
1248 * second number. The <= comparison will be true if and only if the first
1249 * number is less than or equal to the second number. The > comparison
1250 * will be true if and only if the first number is greater than the second
1251 * number. The >= comparison will be true if and only if the first number
1252 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001253 */
1254int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001255xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1256 int ret = 0;
1257 xmlXPathObjectPtr arg1, arg2;
1258
1259 arg2 = valuePop(ctxt);
1260 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1261 if (arg2 != NULL)
1262 xmlXPathFreeObject(arg2);
1263 ERROR0(XPATH_INVALID_OPERAND);
1264 }
1265
1266 arg1 = valuePop(ctxt);
1267 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1268 if (arg1 != NULL)
1269 xmlXPathFreeObject(arg1);
1270 xmlXPathFreeObject(arg2);
1271 ERROR0(XPATH_INVALID_OPERAND);
1272 }
1273
1274 if (arg1->type != XPATH_NUMBER) {
1275 valuePush(ctxt, arg1);
1276 xmlXPathNumberFunction(ctxt, 1);
1277 arg1 = valuePop(ctxt);
1278 }
1279 if (arg1->type != XPATH_NUMBER) {
1280 xmlXPathFreeObject(arg1);
1281 xmlXPathFreeObject(arg2);
1282 ERROR0(XPATH_INVALID_OPERAND);
1283 }
1284 if (arg2->type != XPATH_NUMBER) {
1285 valuePush(ctxt, arg2);
1286 xmlXPathNumberFunction(ctxt, 1);
1287 arg2 = valuePop(ctxt);
1288 }
1289 if (arg2->type != XPATH_NUMBER) {
1290 xmlXPathFreeObject(arg1);
1291 xmlXPathFreeObject(arg2);
1292 ERROR0(XPATH_INVALID_OPERAND);
1293 }
1294 /*
1295 * Add tests for infinity and nan
1296 * => feedback on 3.4 for Inf and NaN
1297 */
1298 if (inf && strict)
1299 ret = (arg1->floatval < arg2->floatval);
1300 else if (inf && !strict)
1301 ret = (arg1->floatval <= arg2->floatval);
1302 else if (!inf && strict)
1303 ret = (arg1->floatval > arg2->floatval);
1304 else if (!inf && !strict)
1305 ret = (arg1->floatval >= arg2->floatval);
1306 xmlXPathFreeObject(arg1);
1307 xmlXPathFreeObject(arg2);
1308 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001309}
1310
1311/**
1312 * xmlXPathValueFlipSign:
1313 * @ctxt: the XPath Parser context
1314 *
1315 * Implement the unary - operation on an XPath object
1316 * The numeric operators convert their operands to numbers as if
1317 * by calling the number function.
1318 */
1319void
1320xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1321 xmlXPathObjectPtr arg;
1322
1323 POP_FLOAT
1324 arg->floatval = -arg->floatval;
1325 valuePush(ctxt, arg);
1326}
1327
1328/**
1329 * xmlXPathAddValues:
1330 * @ctxt: the XPath Parser context
1331 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001332 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001333 * The numeric operators convert their operands to numbers as if
1334 * by calling the number function.
1335 */
1336void
1337xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1338 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001339 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001340
1341 POP_FLOAT
1342 val = arg->floatval;
1343 xmlXPathFreeObject(arg);
1344
1345 POP_FLOAT
1346 arg->floatval += val;
1347 valuePush(ctxt, arg);
1348}
1349
1350/**
1351 * xmlXPathSubValues:
1352 * @ctxt: the XPath Parser context
1353 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001354 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001355 * The numeric operators convert their operands to numbers as if
1356 * by calling the number function.
1357 */
1358void
1359xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1360 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001361 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001362
1363 POP_FLOAT
1364 val = arg->floatval;
1365 xmlXPathFreeObject(arg);
1366
1367 POP_FLOAT
1368 arg->floatval -= val;
1369 valuePush(ctxt, arg);
1370}
1371
1372/**
1373 * xmlXPathMultValues:
1374 * @ctxt: the XPath Parser context
1375 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001376 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001377 * The numeric operators convert their operands to numbers as if
1378 * by calling the number function.
1379 */
1380void
1381xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1382 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001383 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001384
1385 POP_FLOAT
1386 val = arg->floatval;
1387 xmlXPathFreeObject(arg);
1388
1389 POP_FLOAT
1390 arg->floatval *= val;
1391 valuePush(ctxt, arg);
1392}
1393
1394/**
1395 * xmlXPathDivValues:
1396 * @ctxt: the XPath Parser context
1397 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001398 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001399 * The numeric operators convert their operands to numbers as if
1400 * by calling the number function.
1401 */
1402void
1403xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1404 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001405 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001406
1407 POP_FLOAT
1408 val = arg->floatval;
1409 xmlXPathFreeObject(arg);
1410
1411 POP_FLOAT
1412 arg->floatval /= val;
1413 valuePush(ctxt, arg);
1414}
1415
1416/**
1417 * xmlXPathModValues:
1418 * @ctxt: the XPath Parser context
1419 *
1420 * Implement the div operation on XPath objects: @arg1 / @arg2
1421 * The numeric operators convert their operands to numbers as if
1422 * by calling the number function.
1423 */
1424void
1425xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1426 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001427 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001428
1429 POP_FLOAT
1430 val = arg->floatval;
1431 xmlXPathFreeObject(arg);
1432
1433 POP_FLOAT
1434 arg->floatval /= val;
1435 valuePush(ctxt, arg);
1436}
1437
1438/************************************************************************
1439 * *
1440 * The traversal functions *
1441 * *
1442 ************************************************************************/
1443
1444#define AXIS_ANCESTOR 1
1445#define AXIS_ANCESTOR_OR_SELF 2
1446#define AXIS_ATTRIBUTE 3
1447#define AXIS_CHILD 4
1448#define AXIS_DESCENDANT 5
1449#define AXIS_DESCENDANT_OR_SELF 6
1450#define AXIS_FOLLOWING 7
1451#define AXIS_FOLLOWING_SIBLING 8
1452#define AXIS_NAMESPACE 9
1453#define AXIS_PARENT 10
1454#define AXIS_PRECEDING 11
1455#define AXIS_PRECEDING_SIBLING 12
1456#define AXIS_SELF 13
1457
1458/*
1459 * A traversal function enumerates nodes along an axis.
1460 * Initially it must be called with NULL, and it indicates
1461 * termination on the axis by returning NULL.
1462 */
1463typedef xmlNodePtr (*xmlXPathTraversalFunction)
1464 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1465
1466/**
1467 * mlXPathNextSelf:
1468 * @ctxt: the XPath Parser context
1469 * @cur: the current node in the traversal
1470 *
1471 * Traversal function for the "self" direction
1472 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001473 *
1474 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001475 */
1476xmlNodePtr
1477xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1478 if (cur == NULL)
1479 return(ctxt->context->node);
1480 return(NULL);
1481}
1482
1483/**
1484 * mlXPathNextChild:
1485 * @ctxt: the XPath Parser context
1486 * @cur: the current node in the traversal
1487 *
1488 * Traversal function for the "child" direction
1489 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001490 *
1491 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001492 */
1493xmlNodePtr
1494xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001495 if (cur == NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001496 if ((ctxt->context->node->type == XML_DOCUMENT_NODE) ||
1497 (ctxt->context->node->type == XML_HTML_DOCUMENT_NODE))
1498 return(((xmlDocPtr) ctxt->context->node)->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001499 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001500 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001501 if ((cur->type == XML_DOCUMENT_NODE) ||
1502 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001503 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001504 return(cur->next);
1505}
1506
1507/**
1508 * mlXPathNextDescendant:
1509 * @ctxt: the XPath Parser context
1510 * @cur: the current node in the traversal
1511 *
1512 * Traversal function for the "descendant" direction
1513 * the descendant axis contains the descendants of the context node in document
1514 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001515 *
1516 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001517 */
1518xmlNodePtr
1519xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001520 if (cur == NULL) {
1521 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1522 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001523 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001524 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001525
1526 if (cur->childs != NULL) return(cur->childs);
1527 if (cur->next != NULL) return(cur->next);
1528
1529 do {
1530 cur = cur->parent;
1531 if (cur == NULL) return(NULL);
1532 if (cur == ctxt->context->node) return(NULL);
1533 if (cur->next != NULL) {
1534 cur = cur->next;
1535 return(cur);
1536 }
1537 } while (cur != NULL);
1538 return(cur);
1539}
1540
1541/**
1542 * mlXPathNextDescendantOrSelf:
1543 * @ctxt: the XPath Parser context
1544 * @cur: the current node in the traversal
1545 *
1546 * Traversal function for the "descendant-or-self" direction
1547 * the descendant-or-self axis contains the context node and the descendants
1548 * of the context node in document order; thus the context node is the first
1549 * node on the axis, and the first child of the context node is the second node
1550 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001551 *
1552 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001553 */
1554xmlNodePtr
1555xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1556 if (cur == NULL)
1557 return(ctxt->context->node);
1558
Daniel Veillardb05deb71999-08-10 19:04:08 +00001559 if (cur == (xmlNodePtr) ctxt->context->doc)
1560 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001561 if (cur->childs != NULL) return(cur->childs);
1562 if (cur->next != NULL) return(cur->next);
1563
1564 do {
1565 cur = cur->parent;
1566 if (cur == NULL) return(NULL);
1567 if (cur == ctxt->context->node) return(NULL);
1568 if (cur->next != NULL) {
1569 cur = cur->next;
1570 return(cur);
1571 }
1572 } while (cur != NULL);
1573 return(cur);
1574}
1575
1576/**
1577 * xmlXPathNextParent:
1578 * @ctxt: the XPath Parser context
1579 * @cur: the current node in the traversal
1580 *
1581 * Traversal function for the "parent" direction
1582 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001583 *
1584 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001585 */
1586xmlNodePtr
1587xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1588 /*
1589 * !!!!!!!!!!!!!
1590 * the parent of an attribute or namespace node is the element
1591 * to which the attribute or namespace node is attached
1592 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001593 if (cur == NULL) {
1594 if (ctxt->context->node->parent == NULL)
1595 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001596 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001597 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001598 return(NULL);
1599}
1600
1601/**
1602 * xmlXPathNextAncestor:
1603 * @ctxt: the XPath Parser context
1604 * @cur: the current node in the traversal
1605 *
1606 * Traversal function for the "ancestor" direction
1607 * the ancestor axis contains the ancestors of the context node; the ancestors
1608 * of the context node consist of the parent of context node and the parent's
1609 * parent and so on; the nodes are ordered in reverse document order; thus the
1610 * parent is the first node on the axis, and the parent's parent is the second
1611 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001612 *
1613 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001614 */
1615xmlNodePtr
1616xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1617 /*
1618 * !!!!!!!!!!!!!
1619 * the parent of an attribute or namespace node is the element
1620 * to which the attribute or namespace node is attached
1621 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001622 if (cur == NULL) {
1623 if (ctxt->context->node->parent == NULL)
1624 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001625 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001626 }
1627 if (cur == ctxt->context->doc->root)
1628 return((xmlNodePtr) ctxt->context->doc);
1629 if (cur == (xmlNodePtr) ctxt->context->doc)
1630 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001631 return(cur->parent);
1632}
1633
1634/**
1635 * xmlXPathNextAncestorOrSelf:
1636 * @ctxt: the XPath Parser context
1637 * @cur: the current node in the traversal
1638 *
1639 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001640 * he ancestor-or-self axis contains the context node and ancestors of
1641 * the context node in reverse document order; thus the context node is
1642 * the first node on the axis, and the context node's parent the second;
1643 * parent here is defined the same as with the parent axis.
1644 *
1645 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001646 */
1647xmlNodePtr
1648xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1649 /*
1650 * !!!!!!!!!!!!!
1651 * the parent of an attribute or namespace node is the element
1652 * to which the attribute or namespace node is attached
1653 */
1654 if (cur == NULL)
1655 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001656 if (cur == ctxt->context->doc->root)
1657 return((xmlNodePtr) ctxt->context->doc);
1658 if (cur == (xmlNodePtr) ctxt->context->doc)
1659 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001660 return(cur->parent);
1661}
1662
1663/**
1664 * xmlXPathNextFollowingSibling:
1665 * @ctxt: the XPath Parser context
1666 * @cur: the current node in the traversal
1667 *
1668 * Traversal function for the "following-sibling" direction
1669 * The following-sibling axis contains the following siblings of the context
1670 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001671 *
1672 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001673 */
1674xmlNodePtr
1675xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001676 if (cur == (xmlNodePtr) ctxt->context->doc)
1677 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001678 if (cur == NULL)
1679 return(ctxt->context->node->next);
1680 return(cur->next);
1681}
1682
1683/**
1684 * xmlXPathNextPrecedingSibling:
1685 * @ctxt: the XPath Parser context
1686 * @cur: the current node in the traversal
1687 *
1688 * Traversal function for the "preceding-sibling" direction
1689 * The preceding-sibling axis contains the preceding siblings of the context
1690 * node in reverse document order; the first preceding sibling is first on the
1691 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001692 *
1693 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001694 */
1695xmlNodePtr
1696xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001697 if (cur == (xmlNodePtr) ctxt->context->doc)
1698 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001699 if (cur == NULL)
1700 return(ctxt->context->node->prev);
1701 return(cur->prev);
1702}
1703
1704/**
1705 * xmlXPathNextFollowing:
1706 * @ctxt: the XPath Parser context
1707 * @cur: the current node in the traversal
1708 *
1709 * Traversal function for the "following" direction
1710 * The following axis contains all nodes in the same document as the context
1711 * node that are after the context node in document order, excluding any
1712 * descendants and excluding attribute nodes and namespace nodes; the nodes
1713 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001714 *
1715 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001716 */
1717xmlNodePtr
1718xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001719 if (cur == (xmlNodePtr) ctxt->context->doc)
1720 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001721 if (cur == NULL)
1722 return(ctxt->context->node->next);; /* !!!!!!!!! */
1723 if (cur->childs != NULL) return(cur->childs);
1724 if (cur->next != NULL) return(cur->next);
1725
1726 do {
1727 cur = cur->parent;
1728 if (cur == NULL) return(NULL);
1729 if (cur == ctxt->context->doc->root) return(NULL);
1730 if (cur->next != NULL) {
1731 cur = cur->next;
1732 return(cur);
1733 }
1734 } while (cur != NULL);
1735 return(cur);
1736}
1737
1738/**
1739 * xmlXPathNextPreceding:
1740 * @ctxt: the XPath Parser context
1741 * @cur: the current node in the traversal
1742 *
1743 * Traversal function for the "preceding" direction
1744 * the preceding axis contains all nodes in the same document as the context
1745 * node that are before the context node in document order, excluding any
1746 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1747 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001748 *
1749 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001750 */
1751xmlNodePtr
1752xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001753 if (cur == (xmlNodePtr) ctxt->context->doc)
1754 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001755 if (cur == NULL)
1756 return(ctxt->context->node->prev); /* !!!!!!!!! */
1757 if (cur->last != NULL) return(cur->last);
1758 if (cur->prev != NULL) return(cur->prev);
1759
1760 do {
1761 cur = cur->parent;
1762 if (cur == NULL) return(NULL);
1763 if (cur == ctxt->context->doc->root) return(NULL);
1764 if (cur->prev != NULL) {
1765 cur = cur->prev;
1766 return(cur);
1767 }
1768 } while (cur != NULL);
1769 return(cur);
1770}
1771
1772/**
1773 * xmlXPathNextNamespace:
1774 * @ctxt: the XPath Parser context
1775 * @cur: the current attribute in the traversal
1776 *
1777 * Traversal function for the "namespace" direction
1778 * the namespace axis contains the namespace nodes of the context node;
1779 * the order of nodes on this axis is implementation-defined; the axis will
1780 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001781 *
1782 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001783 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001784xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001785xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001786 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1787 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001788 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001789 ctxt->context->namespaces =
1790 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1791 if (ctxt->context->namespaces == NULL) return(NULL);
1792 ctxt->context->nsNr = 0;
1793 }
1794 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001795}
1796
1797/**
1798 * xmlXPathNextAttribute:
1799 * @ctxt: the XPath Parser context
1800 * @cur: the current attribute in the traversal
1801 *
1802 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001803 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001804 *
1805 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001806 */
1807xmlAttrPtr
1808xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001809 if (cur == NULL) {
1810 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1811 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001812 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001813 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001814 return(cur->next);
1815}
1816
1817/************************************************************************
1818 * *
1819 * NodeTest Functions *
1820 * *
1821 ************************************************************************/
1822
1823#define NODE_TEST_NONE 0
1824#define NODE_TEST_TYPE 1
1825#define NODE_TEST_PI 2
1826#define NODE_TEST_ALL 3
1827#define NODE_TEST_NS 4
1828#define NODE_TEST_NAME 5
1829
1830#define NODE_TYPE_COMMENT 50
1831#define NODE_TYPE_TEXT 51
1832#define NODE_TYPE_PI 52
1833#define NODE_TYPE_NODE 53
1834
1835#define IS_FUNCTION 200
1836
1837/**
1838 * xmlXPathNodeCollectAndTest:
1839 * @ctxt: the XPath Parser context
1840 * @cur: the current node to test
1841 *
1842 * This is the function implementing a step: based on the current list
1843 * of nodes, it builds up a new list, looking at all nodes under that
1844 * axis and selecting them.
1845 *
1846 * Returns the new NodeSet resulting from the search.
1847 */
1848xmlNodeSetPtr
1849xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001850 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001851#ifdef DEBUG_STEP
1852 int n = 0, t = 0;
1853#endif
1854 int i;
1855 xmlNodeSetPtr ret;
1856 xmlXPathTraversalFunction next = NULL;
1857 xmlNodePtr cur = NULL;
1858
1859 if (ctxt->context->nodelist == NULL) {
1860 if (ctxt->context->node == NULL) {
1861 fprintf(xmlXPathDebug,
1862 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1863 __FILE__, __LINE__);
1864 return(NULL);
1865 }
1866 STRANGE
1867 return(NULL);
1868 }
1869#ifdef DEBUG_STEP
1870 fprintf(xmlXPathDebug, "new step : ");
1871#endif
1872 switch (axis) {
1873 case AXIS_ANCESTOR:
1874#ifdef DEBUG_STEP
1875 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1876#endif
1877 next = xmlXPathNextAncestor; break;
1878 case AXIS_ANCESTOR_OR_SELF:
1879#ifdef DEBUG_STEP
1880 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1881#endif
1882 next = xmlXPathNextAncestorOrSelf; break;
1883 case AXIS_ATTRIBUTE:
1884#ifdef DEBUG_STEP
1885 fprintf(xmlXPathDebug, "axis 'attributes' ");
1886#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001887 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001888 break;
1889 case AXIS_CHILD:
1890#ifdef DEBUG_STEP
1891 fprintf(xmlXPathDebug, "axis 'child' ");
1892#endif
1893 next = xmlXPathNextChild; break;
1894 case AXIS_DESCENDANT:
1895#ifdef DEBUG_STEP
1896 fprintf(xmlXPathDebug, "axis 'descendant' ");
1897#endif
1898 next = xmlXPathNextDescendant; break;
1899 case AXIS_DESCENDANT_OR_SELF:
1900#ifdef DEBUG_STEP
1901 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1902#endif
1903 next = xmlXPathNextDescendantOrSelf; break;
1904 case AXIS_FOLLOWING:
1905#ifdef DEBUG_STEP
1906 fprintf(xmlXPathDebug, "axis 'following' ");
1907#endif
1908 next = xmlXPathNextFollowing; break;
1909 case AXIS_FOLLOWING_SIBLING:
1910#ifdef DEBUG_STEP
1911 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1912#endif
1913 next = xmlXPathNextFollowingSibling; break;
1914 case AXIS_NAMESPACE:
1915#ifdef DEBUG_STEP
1916 fprintf(xmlXPathDebug, "axis 'namespace' ");
1917#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001918 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001919 break;
1920 case AXIS_PARENT:
1921#ifdef DEBUG_STEP
1922 fprintf(xmlXPathDebug, "axis 'parent' ");
1923#endif
1924 next = xmlXPathNextParent; break;
1925 case AXIS_PRECEDING:
1926#ifdef DEBUG_STEP
1927 fprintf(xmlXPathDebug, "axis 'preceding' ");
1928#endif
1929 next = xmlXPathNextPreceding; break;
1930 case AXIS_PRECEDING_SIBLING:
1931#ifdef DEBUG_STEP
1932 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1933#endif
1934 next = xmlXPathNextPrecedingSibling; break;
1935 case AXIS_SELF:
1936#ifdef DEBUG_STEP
1937 fprintf(xmlXPathDebug, "axis 'self' ");
1938#endif
1939 next = xmlXPathNextSelf; break;
1940 }
1941 if (next == NULL) return(NULL);
1942 ret = xmlXPathNodeSetCreate(NULL);
1943#ifdef DEBUG_STEP
1944 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1945 ctxt->context->nodelist->nodeNr);
1946 switch (test) {
1947 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001948 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001949 break;
1950 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001951 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001952 break;
1953 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001954 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001955 break;
1956 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001957 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001958 break;
1959 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001960 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001961 prefix);
1962 break;
1963 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001964 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001965 if (prefix != NULL)
1966 fprintf(xmlXPathDebug, " with namespace %s\n",
1967 prefix);
1968 break;
1969 }
1970 fprintf(xmlXPathDebug, "Testing : ");
1971#endif
1972 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1973 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1974
1975 cur = NULL;
1976 do {
1977 cur = next(ctxt, cur);
1978 if (cur == NULL) break;
1979#ifdef DEBUG_STEP
1980 t++;
1981 fprintf(xmlXPathDebug, " %s", cur->name);
1982#endif
1983 switch (test) {
1984 case NODE_TEST_NONE:
1985 STRANGE
1986 return(NULL);
1987 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001988 if ((cur->type == type) ||
1989 ((type == XML_ELEMENT_NODE) &&
1990 ((cur->type == XML_DOCUMENT_NODE) ||
1991 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001992#ifdef DEBUG_STEP
1993 n++;
1994#endif
1995 xmlXPathNodeSetAdd(ret, cur);
1996 }
1997 break;
1998 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001999 if (cur->type == XML_PI_NODE) {
2000 if ((name != NULL) &&
2001 (xmlStrcmp(name, cur->name)))
2002 break;
2003#ifdef DEBUG_STEP
2004 n++;
2005#endif
2006 xmlXPathNodeSetAdd(ret, cur);
2007 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002008 break;
2009 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002010 if ((cur->type == XML_ELEMENT_NODE) ||
2011 (cur->type == XML_ATTRIBUTE_NODE)) {
2012 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002013#ifdef DEBUG_STEP
2014 n++;
2015#endif
2016 xmlXPathNodeSetAdd(ret, cur);
2017 }
2018 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002019 case NODE_TEST_NS: {
2020 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002021 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002022 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002023 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002024 switch (cur->type) {
2025 case XML_ELEMENT_NODE:
2026 if (!xmlStrcmp(name, cur->name) &&
2027 (((prefix == NULL) ||
2028 ((cur->ns != NULL) &&
2029 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002030#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002031 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002032#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002033 xmlXPathNodeSetAdd(ret, cur);
2034 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002035 break;
2036 case XML_ATTRIBUTE_NODE: {
2037 xmlAttrPtr attr = (xmlAttrPtr) cur;
2038 if (!xmlStrcmp(name, attr->name)) {
2039#ifdef DEBUG_STEP
2040 n++;
2041#endif
2042 xmlXPathNodeSetAdd(ret, cur);
2043 }
2044 break;
2045 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002046 default:
2047 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002048 }
2049 break;
2050
2051 }
2052 } while (cur != NULL);
2053 }
2054#ifdef DEBUG_STEP
2055 fprintf(xmlXPathDebug,
2056 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2057#endif
2058 return(ret);
2059}
2060
2061
2062/************************************************************************
2063 * *
2064 * Implicit tree core function library *
2065 * *
2066 ************************************************************************/
2067
2068/**
2069 * xmlXPathRoot:
2070 * @ctxt: the XPath Parser context
2071 *
2072 * Initialize the context to the root of the document
2073 */
2074void
2075xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2076 if (ctxt->context->nodelist != NULL)
2077 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002078 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2079 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002080}
2081
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002082/************************************************************************
2083 * *
2084 * The explicit core function library *
2085 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2086 * *
2087 ************************************************************************/
2088
2089
2090/**
2091 * xmlXPathLastFunction:
2092 * @ctxt: the XPath Parser context
2093 *
2094 * Implement the last() XPath function
2095 * The last function returns the number of nodes in the context node list.
2096 */
2097void
2098xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2099 CHECK_ARITY(0);
2100 if ((ctxt->context->nodelist == NULL) ||
2101 (ctxt->context->node == NULL) ||
2102 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002103 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002104 } else {
2105 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002106 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002107 }
2108}
2109
2110/**
2111 * xmlXPathPositionFunction:
2112 * @ctxt: the XPath Parser context
2113 *
2114 * Implement the position() XPath function
2115 * The position function returns the position of the context node in the
2116 * context node list. The first position is 1, and so the last positionr
2117 * will be equal to last().
2118 */
2119void
2120xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2121 int i;
2122
2123 CHECK_ARITY(0);
2124 if ((ctxt->context->nodelist == NULL) ||
2125 (ctxt->context->node == NULL) ||
2126 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002127 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002128 }
2129 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2130 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002131 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002132 return;
2133 }
2134 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002135 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002136}
2137
2138/**
2139 * xmlXPathCountFunction:
2140 * @ctxt: the XPath Parser context
2141 *
2142 * Implement the count() XPath function
2143 */
2144void
2145xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2146 xmlXPathObjectPtr cur;
2147
2148 CHECK_ARITY(1);
2149 CHECK_TYPE(XPATH_NODESET);
2150 cur = valuePop(ctxt);
2151
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002152 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002153 xmlXPathFreeObject(cur);
2154}
2155
2156/**
2157 * xmlXPathIdFunction:
2158 * @ctxt: the XPath Parser context
2159 *
2160 * Implement the id() XPath function
2161 * The id function selects elements by their unique ID
2162 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2163 * then the result is the union of the result of applying id to the
2164 * string value of each of the nodes in the argument node-set. When the
2165 * argument to id is of any other type, the argument is converted to a
2166 * string as if by a call to the string function; the string is split
2167 * into a whitespace-separated list of tokens (whitespace is any sequence
2168 * of characters matching the production S); the result is a node-set
2169 * containing the elements in the same document as the context node that
2170 * have a unique ID equal to any of the tokens in the list.
2171 */
2172void
2173xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002174 const xmlChar *tokens;
2175 const xmlChar *cur;
2176 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002177 xmlAttrPtr attr;
2178 xmlNodePtr elem = NULL;
2179 xmlXPathObjectPtr ret, obj;
2180
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002181 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002182 obj = valuePop(ctxt);
2183 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2184 if (obj->type == XPATH_NODESET) {
2185 TODO /* ID function in case of NodeSet */
2186 }
2187 if (obj->type != XPATH_STRING) {
2188 valuePush(ctxt, obj);
2189 xmlXPathStringFunction(ctxt, 1);
2190 obj = valuePop(ctxt);
2191 if (obj->type != XPATH_STRING) {
2192 xmlXPathFreeObject(obj);
2193 return;
2194 }
2195 }
2196 tokens = obj->stringval;
2197
2198 ret = xmlXPathNewNodeSet(NULL);
2199 valuePush(ctxt, ret);
2200 if (tokens == NULL) {
2201 xmlXPathFreeObject(obj);
2202 return;
2203 }
2204
2205 cur = tokens;
2206
2207 while (IS_BLANK(*cur)) cur++;
2208 while (*cur != 0) {
2209 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2210 (*cur == '.') || (*cur == '-') ||
2211 (*cur == '_') || (*cur == ':') ||
2212 (IS_COMBINING(*cur)) ||
2213 (IS_EXTENDER(*cur)))
2214 cur++;
2215
2216 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2217
2218 ID = xmlStrndup(tokens, cur - tokens);
2219 attr = xmlGetID(ctxt->context->doc, ID);
2220 if (attr != NULL) {
2221 elem = attr->node;
2222 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2223 }
2224 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002225 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002226
2227 while (IS_BLANK(*cur)) cur++;
2228 tokens = cur;
2229 }
2230 xmlXPathFreeObject(obj);
2231 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002232}
2233
2234/**
2235 * xmlXPathLocalPartFunction:
2236 * @ctxt: the XPath Parser context
2237 *
2238 * Implement the local-part() XPath function
2239 * The local-part function returns a string containing the local part
2240 * of the name of the node in the argument node-set that is first in
2241 * document order. If the node-set is empty or the first node has no
2242 * name, an empty string is returned. If the argument is omitted it
2243 * defaults to the context node.
2244 */
2245void
2246xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2247 xmlXPathObjectPtr cur;
2248
2249 CHECK_ARITY(1);
2250 CHECK_TYPE(XPATH_NODESET);
2251 cur = valuePop(ctxt);
2252
2253 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002254 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002255 } else {
2256 int i = 0; /* Should be first in document order !!!!! */
2257 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2258 }
2259 xmlXPathFreeObject(cur);
2260}
2261
2262/**
2263 * xmlXPathNamespaceFunction:
2264 * @ctxt: the XPath Parser context
2265 *
2266 * Implement the namespace() XPath function
2267 * The namespace function returns a string containing the namespace URI
2268 * of the expanded name of the node in the argument node-set that is
2269 * first in document order. If the node-set is empty, the first node has
2270 * no name, or the expanded name has no namespace URI, an empty string
2271 * is returned. If the argument is omitted it defaults to the context node.
2272 */
2273void
2274xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2275 xmlXPathObjectPtr cur;
2276
Daniel Veillardb96e6431999-08-29 21:02:19 +00002277 if (nargs == 0) {
2278 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2279 nargs = 1;
2280 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002281 CHECK_ARITY(1);
2282 CHECK_TYPE(XPATH_NODESET);
2283 cur = valuePop(ctxt);
2284
2285 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002286 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002287 } else {
2288 int i = 0; /* Should be first in document order !!!!! */
2289
2290 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002291 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002292 else
2293 valuePush(ctxt, xmlXPathNewString(
2294 cur->nodesetval->nodeTab[i]->ns->href));
2295 }
2296 xmlXPathFreeObject(cur);
2297}
2298
2299/**
2300 * xmlXPathNameFunction:
2301 * @ctxt: the XPath Parser context
2302 *
2303 * Implement the name() XPath function
2304 * The name function returns a string containing a QName representing
2305 * the name of the node in the argument node-set that is first in documenti
2306 * order. The QName must represent the name with respect to the namespace
2307 * declarations in effect on the node whose name is being represented.
2308 * Typically, this will be the form in which the name occurred in the XML
2309 * source. This need not be the case if there are namespace declarations
2310 * in effect on the node that associate multiple prefixes with the same
2311 * namespace. However, an implementation may include information about
2312 * the original prefix in its representation of nodes; in this case, an
2313 * implementation can ensure that the returned string is always the same
2314 * as the QName used in the XML source. If the argument it omitted it
2315 * defaults to the context node.
2316 * Libxml keep the original prefix so the "real qualified name" used is
2317 * returned.
2318 */
2319void
2320xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2321 xmlXPathObjectPtr cur;
2322
2323 CHECK_ARITY(1);
2324 CHECK_TYPE(XPATH_NODESET);
2325 cur = valuePop(ctxt);
2326
2327 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002328 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002329 } else {
2330 int i = 0; /* Should be first in document order !!!!! */
2331
2332 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2333 valuePush(ctxt, xmlXPathNewString(
2334 cur->nodesetval->nodeTab[i]->name));
2335
2336 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002337 char name[2000];
2338 sprintf(name, "%s:%s",
2339 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2340 (char *) cur->nodesetval->nodeTab[i]->name);
2341 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002342 }
2343 }
2344 xmlXPathFreeObject(cur);
2345}
2346
2347/**
2348 * xmlXPathStringFunction:
2349 * @ctxt: the XPath Parser context
2350 *
2351 * Implement the string() XPath function
2352 * he string function converts an object to a string as follows:
2353 * - A node-set is converted to a string by returning the value of
2354 * the node in the node-set that is first in document order.
2355 * If the node-set is empty, an empty string is returned.
2356 * - A number is converted to a string as follows
2357 * + NaN is converted to the string NaN
2358 * + positive zero is converted to the string 0
2359 * + negative zero is converted to the string 0
2360 * + positive infinity is converted to the string Infinity
2361 * + negative infinity is converted to the string -Infinity
2362 * + if the number is an integer, the number is represented in
2363 * decimal form as a Number with no decimal point and no leading
2364 * zeros, preceded by a minus sign (-) if the number is negative
2365 * + otherwise, the number is represented in decimal form as a
2366 * Number including a decimal point with at least one digit
2367 * before the decimal point and at least one digit after the
2368 * decimal point, preceded by a minus sign (-) if the number
2369 * is negative; there must be no leading zeros before the decimal
2370 * point apart possibly from the one required digit immediatelyi
2371 * before the decimal point; beyond the one required digit
2372 * after the decimal point there must be as many, but only as
2373 * many, more digits as are needed to uniquely distinguish the
2374 * number from all other IEEE 754 numeric values.
2375 * - The boolean false value is converted to the string false.
2376 * The boolean true value is converted to the string true.
2377 */
2378void
2379xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2380 xmlXPathObjectPtr cur;
2381
2382 CHECK_ARITY(1);
2383 cur = valuePop(ctxt);
2384 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2385 switch (cur->type) {
2386 case XPATH_NODESET:
2387 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002388 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002389 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002390 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002391 int i = 0; /* Should be first in document order !!!!! */
2392 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2393 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002394 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002395 }
2396 xmlXPathFreeObject(cur);
2397 return;
2398 case XPATH_STRING:
2399 valuePush(ctxt, cur);
2400 return;
2401 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002402 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2403 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002404 xmlXPathFreeObject(cur);
2405 return;
2406 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002407 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002408
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002409 if (isnan(cur->floatval))
2410 sprintf(buf, "NaN");
2411 else if (isinf(cur->floatval) > 0)
2412 sprintf(buf, "+Infinity");
2413 else if (isinf(cur->floatval) < 0)
2414 sprintf(buf, "-Infinity");
2415 else
2416 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002417 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002418 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002419 return;
2420 }
2421 }
2422 STRANGE
2423}
2424
2425/**
2426 * xmlXPathStringLengthFunction:
2427 * @ctxt: the XPath Parser context
2428 *
2429 * Implement the string-length() XPath function
2430 * The string-length returns the number of characters in the string
2431 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2432 * the context node converted to a string, in other words the value
2433 * of the context node.
2434 */
2435void
2436xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2437 xmlXPathObjectPtr cur;
2438
2439 if (nargs == 0) {
2440 if (ctxt->context->node == NULL) {
2441 valuePush(ctxt, xmlXPathNewFloat(0));
2442 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002443 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002444
2445 content = xmlNodeGetContent(ctxt->context->node);
2446 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002447 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002448 }
2449 return;
2450 }
2451 CHECK_ARITY(1);
2452 CHECK_TYPE(XPATH_STRING);
2453 cur = valuePop(ctxt);
2454 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2455 xmlXPathFreeObject(cur);
2456}
2457
2458/**
2459 * xmlXPathConcatFunction:
2460 * @ctxt: the XPath Parser context
2461 *
2462 * Implement the concat() XPath function
2463 * The concat function returns the concatenation of its arguments.
2464 */
2465void
2466xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2467 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002468 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002469
2470 if (nargs < 2) {
2471 CHECK_ARITY(2);
2472 }
2473
2474 cur = valuePop(ctxt);
2475 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2476 xmlXPathFreeObject(cur);
2477 return;
2478 }
2479 nargs--;
2480
2481 while (nargs > 0) {
2482 new = valuePop(ctxt);
2483 if ((new == NULL) || (new->type != XPATH_STRING)) {
2484 xmlXPathFreeObject(new);
2485 xmlXPathFreeObject(cur);
2486 ERROR(XPATH_INVALID_TYPE);
2487 }
2488 tmp = xmlStrcat(new->stringval, cur->stringval);
2489 new->stringval = cur->stringval;
2490 cur->stringval = tmp;
2491
2492 xmlXPathFreeObject(new);
2493 nargs--;
2494 }
2495 valuePush(ctxt, cur);
2496}
2497
2498/**
2499 * xmlXPathContainsFunction:
2500 * @ctxt: the XPath Parser context
2501 *
2502 * Implement the contains() XPath function
2503 * The contains function returns true if the first argument string
2504 * contains the second argument string, and otherwise returns false.
2505 */
2506void
2507xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2508 xmlXPathObjectPtr hay, needle;
2509
2510 CHECK_ARITY(2);
2511 CHECK_TYPE(XPATH_STRING);
2512 needle = valuePop(ctxt);
2513 hay = valuePop(ctxt);
2514 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2515 xmlXPathFreeObject(hay);
2516 xmlXPathFreeObject(needle);
2517 ERROR(XPATH_INVALID_TYPE);
2518 }
2519 if (xmlStrstr(hay->stringval, needle->stringval))
2520 valuePush(ctxt, xmlXPathNewBoolean(1));
2521 else
2522 valuePush(ctxt, xmlXPathNewBoolean(0));
2523 xmlXPathFreeObject(hay);
2524 xmlXPathFreeObject(needle);
2525}
2526
2527/**
2528 * xmlXPathStartsWithFunction:
2529 * @ctxt: the XPath Parser context
2530 *
2531 * Implement the starts-with() XPath function
2532 * The starts-with function returns true if the first argument string
2533 * starts with the second argument string, and otherwise returns false.
2534 */
2535void
2536xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2537 xmlXPathObjectPtr hay, needle;
2538 int n;
2539
2540 CHECK_ARITY(2);
2541 CHECK_TYPE(XPATH_STRING);
2542 needle = valuePop(ctxt);
2543 hay = valuePop(ctxt);
2544 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2545 xmlXPathFreeObject(hay);
2546 xmlXPathFreeObject(needle);
2547 ERROR(XPATH_INVALID_TYPE);
2548 }
2549 n = xmlStrlen(needle->stringval);
2550 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2551 valuePush(ctxt, xmlXPathNewBoolean(0));
2552 else
2553 valuePush(ctxt, xmlXPathNewBoolean(1));
2554 xmlXPathFreeObject(hay);
2555 xmlXPathFreeObject(needle);
2556}
2557
2558/**
2559 * xmlXPathSubstringFunction:
2560 * @ctxt: the XPath Parser context
2561 *
2562 * Implement the substring() XPath function
2563 * The substring function returns the substring of the first argument
2564 * starting at the position specified in the second argument with
2565 * length specified in the third argument. For example,
2566 * substring("12345",2,3) returns "234". If the third argument is not
2567 * specified, it returns the substring starting at the position specified
2568 * in the second argument and continuing to the end of the string. For
2569 * example, substring("12345",2) returns "2345". More precisely, each
2570 * character in the string (see [3.6 Strings]) is considered to have a
2571 * numeric position: the position of the first character is 1, the position
2572 * of the second character is 2 and so on. The returned substring contains
2573 * those characters for which the position of the character is greater than
2574 * or equal to the second argument and, if the third argument is specified,
2575 * less than the sum of the second and third arguments; the comparisons
2576 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2577 * - substring("12345", 1.5, 2.6) returns "234"
2578 * - substring("12345", 0, 3) returns "12"
2579 * - substring("12345", 0 div 0, 3) returns ""
2580 * - substring("12345", 1, 0 div 0) returns ""
2581 * - substring("12345", -42, 1 div 0) returns "12345"
2582 * - substring("12345", -1 div 0, 1 div 0) returns ""
2583 */
2584void
2585xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2586 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002587 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002588 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002589 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002590
2591 /*
2592 * Conformance needs to be checked !!!!!
2593 */
2594 if (nargs < 2) {
2595 CHECK_ARITY(2);
2596 }
2597 if (nargs > 3) {
2598 CHECK_ARITY(3);
2599 }
2600 if (nargs == 3) {
2601 CHECK_TYPE(XPATH_NUMBER);
2602 len = valuePop(ctxt);
2603 le = len->floatval;
2604 xmlXPathFreeObject(len);
2605 } else {
2606 le = 2000000000;
2607 }
2608 CHECK_TYPE(XPATH_NUMBER);
2609 start = valuePop(ctxt);
2610 in = start->floatval;
2611 xmlXPathFreeObject(start);
2612 CHECK_TYPE(XPATH_STRING);
2613 str = valuePop(ctxt);
2614 le += in;
2615
2616 /* integer index of the first char */
2617 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002618 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002619
2620 /* integer index of the last char */
2621 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002622 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002623
2624 /* back to a zero based len */
2625 i--;
2626 l--;
2627
2628 /* check against the string len */
2629 if (l > 1024) {
2630 l = xmlStrlen(str->stringval);
2631 }
2632 if (i < 0) {
2633 i = 0;
2634 }
2635
2636 /* number of chars to copy */
2637 l -= i;
2638
2639 ret = xmlStrsub(str->stringval, i, l);
2640 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002641 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002642 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002643 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002644 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002645 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002646 xmlXPathFreeObject(str);
2647}
2648
2649/**
2650 * xmlXPathSubstringBeforeFunction:
2651 * @ctxt: the XPath Parser context
2652 *
2653 * Implement the substring-before() XPath function
2654 * The substring-before function returns the substring of the first
2655 * argument string that precedes the first occurrence of the second
2656 * argument string in the first argument string, or the empty string
2657 * if the first argument string does not contain the second argument
2658 * string. For example, substring-before("1999/04/01","/") returns 1999.
2659 */
2660void
2661xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2662 CHECK_ARITY(2);
2663 TODO /* substring before */
2664}
2665
2666/**
2667 * xmlXPathSubstringAfterFunction:
2668 * @ctxt: the XPath Parser context
2669 *
2670 * Implement the substring-after() XPath function
2671 * The substring-after function returns the substring of the first
2672 * argument string that follows the first occurrence of the second
2673 * argument string in the first argument string, or the empty stringi
2674 * if the first argument string does not contain the second argument
2675 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2676 * and substring-after("1999/04/01","19") returns 99/04/01.
2677 */
2678void
2679xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2680 CHECK_ARITY(2);
2681 TODO /* substring after */
2682}
2683
2684/**
2685 * xmlXPathNormalizeFunction:
2686 * @ctxt: the XPath Parser context
2687 *
2688 * Implement the normalize() XPath function
2689 * The normalize function returns the argument string with white
2690 * space normalized by stripping leading and trailing whitespace
2691 * and replacing sequences of whitespace characters by a single
2692 * space. Whitespace characters are the same allowed by the S production
2693 * in XML. If the argument is omitted, it defaults to the context
2694 * node converted to a string, in other words the value of the context node.
2695 */
2696void
2697xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2698 CHECK_ARITY(1);
2699 TODO /* normalize isn't as boring as translate, but pretty much */
2700}
2701
2702/**
2703 * xmlXPathTranslateFunction:
2704 * @ctxt: the XPath Parser context
2705 *
2706 * Implement the translate() XPath function
2707 * The translate function returns the first argument string with
2708 * occurrences of characters in the second argument string replaced
2709 * by the character at the corresponding position in the third argument
2710 * string. For example, translate("bar","abc","ABC") returns the string
2711 * BAr. If there is a character in the second argument string with no
2712 * character at a corresponding position in the third argument string
2713 * (because the second argument string is longer than the third argument
2714 * string), then occurrences of that character in the first argument
2715 * string are removed. For example, translate("--aaa--","abc-","ABC")
2716 * returns "AAA". If a character occurs more than once in second
2717 * argument string, then the first occurrence determines the replacement
2718 * character. If the third argument string is longer than the second
2719 * argument string, then excess characters are ignored.
2720 */
2721void
2722xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2723 CHECK_ARITY(3);
2724 TODO /* translate is boring, waiting for UTF-8 representation too */
2725}
2726
2727/**
2728 * xmlXPathBooleanFunction:
2729 * @ctxt: the XPath Parser context
2730 *
2731 * Implement the boolean() XPath function
2732 * he boolean function converts its argument to a boolean as follows:
2733 * - a number is true if and only if it is neither positive or
2734 * negative zero nor NaN
2735 * - a node-set is true if and only if it is non-empty
2736 * - a string is true if and only if its length is non-zero
2737 */
2738void
2739xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2740 xmlXPathObjectPtr cur;
2741 int res = 0;
2742
2743 CHECK_ARITY(1);
2744 cur = valuePop(ctxt);
2745 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2746 switch (cur->type) {
2747 case XPATH_NODESET:
2748 if ((cur->nodesetval == NULL) ||
2749 (cur->nodesetval->nodeNr == 0)) res = 0;
2750 else
2751 res = 1;
2752 break;
2753 case XPATH_STRING:
2754 if ((cur->stringval == NULL) ||
2755 (cur->stringval[0] == 0)) res = 0;
2756 else
2757 res = 1;
2758 break;
2759 case XPATH_BOOLEAN:
2760 valuePush(ctxt, cur);
2761 return;
2762 case XPATH_NUMBER:
2763 if (cur->floatval) res = 1;
2764 break;
2765 default:
2766 STRANGE
2767 }
2768 xmlXPathFreeObject(cur);
2769 valuePush(ctxt, xmlXPathNewBoolean(res));
2770}
2771
2772/**
2773 * xmlXPathNotFunction:
2774 * @ctxt: the XPath Parser context
2775 *
2776 * Implement the not() XPath function
2777 * The not function returns true if its argument is false,
2778 * and false otherwise.
2779 */
2780void
2781xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2782 CHECK_ARITY(1);
2783 CHECK_TYPE(XPATH_BOOLEAN);
2784 ctxt->value->boolval = ! ctxt->value->boolval;
2785}
2786
2787/**
2788 * xmlXPathTrueFunction:
2789 * @ctxt: the XPath Parser context
2790 *
2791 * Implement the true() XPath function
2792 */
2793void
2794xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2795 CHECK_ARITY(0);
2796 valuePush(ctxt, xmlXPathNewBoolean(1));
2797}
2798
2799/**
2800 * xmlXPathFalseFunction:
2801 * @ctxt: the XPath Parser context
2802 *
2803 * Implement the false() XPath function
2804 */
2805void
2806xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2807 CHECK_ARITY(0);
2808 valuePush(ctxt, xmlXPathNewBoolean(0));
2809}
2810
2811/**
2812 * xmlXPathLangFunction:
2813 * @ctxt: the XPath Parser context
2814 *
2815 * Implement the lang() XPath function
2816 * The lang function returns true or false depending on whether the
2817 * language of the context node as specified by xml:lang attributes
2818 * is the same as or is a sublanguage of the language specified by
2819 * the argument string. The language of the context node is determined
2820 * by the value of the xml:lang attribute on the context node, or, if
2821 * the context node has no xml:lang attribute, by the value of the
2822 * xml:lang attribute on the nearest ancestor of the context node that
2823 * has an xml:lang attribute. If there is no such attribute, then lang
2824 * returns false. If there is such an attribute, then lang returns
2825 * true if the attribute value is equal to the argument ignoring case,
2826 * or if there is some suffix starting with - such that the attribute
2827 * value is equal to the argument ignoring that suffix of the attribute
2828 * value and ignoring case.
2829 */
2830void
2831xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002832 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002833 const xmlChar *theLang;
2834 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002835 int ret = 0;
2836 int i;
2837
2838 CHECK_ARITY(1);
2839 CHECK_TYPE(XPATH_STRING);
2840 val = valuePop(ctxt);
2841 lang = val->stringval;
2842 theLang = xmlNodeGetLang(ctxt->context->node);
2843 if ((theLang != NULL) && (lang != NULL)) {
2844 for (i = 0;lang[i] != 0;i++)
2845 if (toupper(lang[i]) != toupper(theLang[i]))
2846 goto not_equal;
2847 ret = 1;
2848 }
2849not_equal:
2850 xmlXPathFreeObject(val);
2851 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002852}
2853
2854/**
2855 * xmlXPathNumberFunction:
2856 * @ctxt: the XPath Parser context
2857 *
2858 * Implement the number() XPath function
2859 */
2860void
2861xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2862 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002863 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002864
2865 CHECK_ARITY(1);
2866 cur = valuePop(ctxt);
2867 switch (cur->type) {
2868 case XPATH_NODESET:
2869 valuePush(ctxt, cur);
2870 xmlXPathStringFunction(ctxt, 1);
2871 cur = valuePop(ctxt);
2872 case XPATH_STRING:
2873 res = xmlXPathStringEvalNumber(cur->stringval);
2874 valuePush(ctxt, xmlXPathNewFloat(res));
2875 xmlXPathFreeObject(cur);
2876 return;
2877 case XPATH_BOOLEAN:
2878 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2879 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2880 xmlXPathFreeObject(cur);
2881 return;
2882 case XPATH_NUMBER:
2883 valuePush(ctxt, cur);
2884 return;
2885 }
2886 STRANGE
2887}
2888
2889/**
2890 * xmlXPathSumFunction:
2891 * @ctxt: the XPath Parser context
2892 *
2893 * Implement the sum() XPath function
2894 * The sum function returns the sum of the values of the nodes in
2895 * the argument node-set.
2896 */
2897void
2898xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2899 CHECK_ARITY(1);
2900 TODO /* BUG Sum : don't understand the definition */
2901}
2902
2903/**
2904 * xmlXPathFloorFunction:
2905 * @ctxt: the XPath Parser context
2906 *
2907 * Implement the floor() XPath function
2908 * The floor function returns the largest (closest to positive infinity)
2909 * number that is not greater than the argument and that is an integer.
2910 */
2911void
2912xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2913 CHECK_ARITY(1);
2914 CHECK_TYPE(XPATH_NUMBER);
2915 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002916 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002917}
2918
2919/**
2920 * xmlXPathCeilingFunction:
2921 * @ctxt: the XPath Parser context
2922 *
2923 * Implement the ceiling() XPath function
2924 * The ceiling function returns the smallest (closest to negative infinity)
2925 * number that is not less than the argument and that is an integer.
2926 */
2927void
2928xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002929 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002930
2931 CHECK_ARITY(1);
2932 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002933 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002934 if (f != ctxt->value->floatval)
2935 ctxt->value->floatval = f + 1;
2936}
2937
2938/**
2939 * xmlXPathRoundFunction:
2940 * @ctxt: the XPath Parser context
2941 *
2942 * Implement the round() XPath function
2943 * The round function returns the number that is closest to the
2944 * argument and that is an integer. If there are two such numbers,
2945 * then the one that is even is returned.
2946 */
2947void
2948xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002949 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002950
2951 CHECK_ARITY(1);
2952 CHECK_TYPE(XPATH_NUMBER);
2953 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002954 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002955 if (ctxt->value->floatval < f + 0.5)
2956 ctxt->value->floatval = f;
2957 else if (ctxt->value->floatval == f + 0.5)
2958 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2959 else
2960 ctxt->value->floatval = f + 1;
2961}
2962
2963/************************************************************************
2964 * *
2965 * The Parser *
2966 * *
2967 ************************************************************************/
2968
2969/*
2970 * a couple of forward declarations since we use a recursive call based
2971 * implementation.
2972 */
2973void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2974void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2975void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2976void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2977
2978/**
2979 * xmlXPathParseNCName:
2980 * @ctxt: the XPath Parser context
2981 *
2982 * parse an XML namespace non qualified name.
2983 *
2984 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2985 *
2986 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2987 * CombiningChar | Extender
2988 *
2989 * Returns the namespace name or NULL
2990 */
2991
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002992xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002993xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002994 const xmlChar *q;
2995 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002996
2997 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2998 q = NEXT;
2999
3000 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3001 (CUR == '.') || (CUR == '-') ||
3002 (CUR == '_') ||
3003 (IS_COMBINING(CUR)) ||
3004 (IS_EXTENDER(CUR)))
3005 NEXT;
3006
3007 ret = xmlStrndup(q, CUR_PTR - q);
3008
3009 return(ret);
3010}
3011
3012/**
3013 * xmlXPathParseQName:
3014 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003015 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003016 *
3017 * parse an XML qualified name
3018 *
3019 * [NS 5] QName ::= (Prefix ':')? LocalPart
3020 *
3021 * [NS 6] Prefix ::= NCName
3022 *
3023 * [NS 7] LocalPart ::= NCName
3024 *
3025 * Returns the function returns the local part, and prefix is updated
3026 * to get the Prefix if any.
3027 */
3028
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003029xmlChar *
3030xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3031 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003032
3033 *prefix = NULL;
3034 ret = xmlXPathParseNCName(ctxt);
3035 if (CUR == ':') {
3036 *prefix = ret;
3037 NEXT;
3038 ret = xmlXPathParseNCName(ctxt);
3039 }
3040 return(ret);
3041}
3042
3043/**
3044 * xmlXPathStringEvalNumber:
3045 * @str: A string to scan
3046 *
3047 * [30] Number ::= Digits ('.' Digits)?
3048 * | '.' Digits
3049 * [31] Digits ::= [0-9]+
3050 *
3051 * Parse and evaluate a Number in the string
3052 *
3053 * BUG: "1.' is not valid ... James promised correction
3054 * as Digits ('.' Digits?)?
3055 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003056 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003057 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003058double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003059xmlXPathStringEvalNumber(const xmlChar *str) {
3060 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003061 double ret = 0.0;
3062 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003063 int ok = 0;
3064
3065 while (*cur == ' ') cur++;
3066 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003067 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003068 }
3069 while ((*cur >= '0') && (*cur <= '9')) {
3070 ret = ret * 10 + (*cur - '0');
3071 ok = 1;
3072 cur++;
3073 }
3074 if (*cur == '.') {
3075 cur++;
3076 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003077 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003078 }
3079 while ((*cur >= '0') && (*cur <= '9')) {
3080 mult /= 10;
3081 ret = ret + (*cur - '0') * mult;
3082 cur++;
3083 }
3084 }
3085 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003086 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003087 return(ret);
3088}
3089
3090/**
3091 * xmlXPathEvalNumber:
3092 * @ctxt: the XPath Parser context
3093 *
3094 * [30] Number ::= Digits ('.' Digits)?
3095 * | '.' Digits
3096 * [31] Digits ::= [0-9]+
3097 *
3098 * Parse and evaluate a Number, then push it on the stack
3099 *
3100 * BUG: "1.' is not valid ... James promised correction
3101 * as Digits ('.' Digits?)?
3102 */
3103void
3104xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003105 double ret = 0.0;
3106 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003107 int ok = 0;
3108
3109 CHECK_ERROR;
3110 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3111 ERROR(XPATH_NUMBER_ERROR);
3112 }
3113 while ((CUR >= '0') && (CUR <= '9')) {
3114 ret = ret * 10 + (CUR - '0');
3115 ok = 1;
3116 NEXT;
3117 }
3118 if (CUR == '.') {
3119 NEXT;
3120 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3121 ERROR(XPATH_NUMBER_ERROR);
3122 }
3123 while ((CUR >= '0') && (CUR <= '9')) {
3124 mult /= 10;
3125 ret = ret + (CUR - '0') * mult;
3126 NEXT;
3127 }
3128 }
3129 valuePush(ctxt, xmlXPathNewFloat(ret));
3130}
3131
3132/**
3133 * xmlXPathEvalLiteral:
3134 * @ctxt: the XPath Parser context
3135 *
3136 * Parse a Literal and push it on the stack.
3137 *
3138 * [29] Literal ::= '"' [^"]* '"'
3139 * | "'" [^']* "'"
3140 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003141 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003142 */
3143void
3144xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003145 const xmlChar *q;
3146 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003147
3148 if (CUR == '"') {
3149 NEXT;
3150 q = CUR_PTR;
3151 while ((IS_CHAR(CUR)) && (CUR != '"'))
3152 NEXT;
3153 if (!IS_CHAR(CUR)) {
3154 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3155 } else {
3156 ret = xmlStrndup(q, CUR_PTR - q);
3157 NEXT;
3158 }
3159 } else if (CUR == '\'') {
3160 NEXT;
3161 q = CUR_PTR;
3162 while ((IS_CHAR(CUR)) && (CUR != '\''))
3163 NEXT;
3164 if (!IS_CHAR(CUR)) {
3165 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3166 } else {
3167 ret = xmlStrndup(q, CUR_PTR - q);
3168 NEXT;
3169 }
3170 } else {
3171 ERROR(XPATH_START_LITERAL_ERROR);
3172 }
3173 if (ret == NULL) return;
3174 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003175 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003176}
3177
3178/**
3179 * xmlXPathEvalVariableReference:
3180 * @ctxt: the XPath Parser context
3181 *
3182 * Parse a VariableReference, evaluate it and push it on the stack.
3183 *
3184 * The variable bindings consist of a mapping from variable names
3185 * to variable values. The value of a variable is an object, which
3186 * of any of the types that are possible for the value of an expression,
3187 * and may also be of additional types not specified here.
3188 *
3189 * Early evaluation is possible since:
3190 * The variable bindings [...] used to evaluate a subexpression are
3191 * always the same as those used to evaluate the containing expression.
3192 *
3193 * [36] VariableReference ::= '$' QName
3194 */
3195void
3196xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003197 xmlChar *name;
3198 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003199 xmlXPathObjectPtr value;
3200
3201 if (CUR != '$') {
3202 ERROR(XPATH_VARIABLE_REF_ERROR);
3203 }
3204 name = xmlXPathParseQName(ctxt, &prefix);
3205 if (name == NULL) {
3206 ERROR(XPATH_VARIABLE_REF_ERROR);
3207 }
3208 value = xmlXPathVariablelookup(ctxt, prefix, name);
3209 if (value == NULL) {
3210 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3211 }
3212 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003213 if (prefix != NULL) xmlFree(prefix);
3214 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003215}
3216
3217
3218/**
3219 * xmlXPathFunctionLookup:
3220 * @ctxt: the XPath Parser context
3221 * @name: a name string
3222 *
3223 * Search for a function of the given name
3224 *
3225 * [35] FunctionName ::= QName - NodeType
3226 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003227 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003228 *
3229 * Returns the xmlXPathFunction if found, or NULL otherwise
3230 */
3231xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003232xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003233 switch (name[0]) {
3234 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003235 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003236 return(xmlXPathBooleanFunction);
3237 break;
3238 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003239 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003240 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003241 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003242 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003243 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003244 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003245 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003246 return(xmlXPathContainsFunction);
3247 break;
3248 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003249 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003250 return(xmlXPathIdFunction);
3251 break;
3252 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003253 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003254 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003255 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003256 return(xmlXPathFloorFunction);
3257 break;
3258 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003259 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003260 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003261 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003262 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003263 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003264 return(xmlXPathLocalPartFunction);
3265 break;
3266 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003267 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003268 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003269 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003270 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003271 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003272 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003273 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3274 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003275 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003276 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003277 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003278 return(xmlXPathNumberFunction);
3279 break;
3280 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003281 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003282 return(xmlXPathPositionFunction);
3283 break;
3284 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003285 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003286 return(xmlXPathRoundFunction);
3287 break;
3288 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003289 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003290 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003291 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003292 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003293 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003294 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003295 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003296 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003297 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003298 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003299 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003300 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003301 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003302 return(xmlXPathSumFunction);
3303 break;
3304 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003305 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003306 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003307 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003308 return(xmlXPathTranslateFunction);
3309 break;
3310 }
3311 return(NULL);
3312}
3313
3314/**
3315 * xmlXPathEvalLocationPathName:
3316 * @ctxt: the XPath Parser context
3317 * @name: a name string
3318 *
3319 * Various names in the beginning of a LocationPath expression
3320 * indicate whether that's an Axis, a node type,
3321 *
3322 * [6] AxisName ::= 'ancestor'
3323 * | 'ancestor-or-self'
3324 * | 'attribute'
3325 * | 'child'
3326 * | 'descendant'
3327 * | 'descendant-or-self'
3328 * | 'following'
3329 * | 'following-sibling'
3330 * | 'namespace'
3331 * | 'parent'
3332 * | 'preceding'
3333 * | 'preceding-sibling'
3334 * | 'self'
3335 * [38] NodeType ::= 'comment'
3336 * | 'text'
3337 * | 'processing-instruction'
3338 * | 'node'
3339 */
3340int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003341xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003342 switch (name[0]) {
3343 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003344 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3345 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3346 return(AXIS_ANCESTOR_OR_SELF);
3347 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003348 break;
3349 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003350 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3351 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003352 break;
3353 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003354 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3355 return(AXIS_DESCENDANT);
3356 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3357 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003358 break;
3359 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003360 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3361 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3362 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003363 break;
3364 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003365 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3366 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003367 break;
3368 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003369 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3370 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3371 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3372 return(AXIS_PRECEDING_SIBLING);
3373 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3374 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003375 break;
3376 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003377 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003378 break;
3379 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003380 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003381 break;
3382 }
3383 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3384 return(0);
3385}
3386
3387/**
3388 * xmlXPathEvalFunctionCall:
3389 * @ctxt: the XPath Parser context
3390 *
3391 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3392 * [17] Argument ::= Expr
3393 *
3394 * Parse and evaluate a function call, the evaluation of all arguments are
3395 * pushed on the stack
3396 */
3397void
3398xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003399 xmlChar *name;
3400 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003401 xmlXPathFunction func;
3402 int nbargs = 0;
3403
3404 name = xmlXPathParseQName(ctxt, &prefix);
3405 if (name == NULL) {
3406 ERROR(XPATH_EXPR_ERROR);
3407 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003408 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003409 func = xmlXPathIsFunction(ctxt, name);
3410 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003411 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003412 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3413 }
3414#ifdef DEBUG_EXPR
3415 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3416#endif
3417
3418 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003419 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003420 ERROR(XPATH_EXPR_ERROR);
3421 }
3422 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003423 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003424
3425 while (CUR != ')') {
3426 xmlXPathEvalExpr(ctxt);
3427 nbargs++;
3428 if (CUR == ')') break;
3429 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003430 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003431 ERROR(XPATH_EXPR_ERROR);
3432 }
3433 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003434 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003435 }
3436 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003437 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003438 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003439 func(ctxt, nbargs);
3440}
3441
3442/**
3443 * xmlXPathEvalPrimaryExpr:
3444 * @ctxt: the XPath Parser context
3445 *
3446 * [15] PrimaryExpr ::= VariableReference
3447 * | '(' Expr ')'
3448 * | Literal
3449 * | Number
3450 * | FunctionCall
3451 *
3452 * Parse and evaluate a primary expression, then push the result on the stack
3453 */
3454void
3455xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003456 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003457 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3458 else if (CUR == '(') {
3459 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003460 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003461 xmlXPathEvalExpr(ctxt);
3462 if (CUR != ')') {
3463 ERROR(XPATH_EXPR_ERROR);
3464 }
3465 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003466 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003467 } else if (IS_DIGIT(CUR)) {
3468 xmlXPathEvalNumber(ctxt);
3469 } else if ((CUR == '\'') || (CUR == '"')) {
3470 xmlXPathEvalLiteral(ctxt);
3471 } else {
3472 xmlXPathEvalFunctionCall(ctxt);
3473 }
3474}
3475
3476/**
3477 * xmlXPathEvalFilterExpr:
3478 * @ctxt: the XPath Parser context
3479 *
3480 * [20] FilterExpr ::= PrimaryExpr
3481 * | FilterExpr Predicate
3482 *
3483 * Parse and evaluate a filter expression, then push the result on the stack
3484 * Square brackets are used to filter expressions in the same way that
3485 * they are used in location paths. It is an error if the expression to
3486 * be filtered does not evaluate to a node-set. The context node list
3487 * used for evaluating the expression in square brackets is the node-set
3488 * to be filtered listed in document order.
3489 */
3490
3491void
3492xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3493 /****
3494 xmlNodeSetPtr oldset = NULL;
3495 xmlXPathObjectPtr arg;
3496 ****/
3497
3498 xmlXPathEvalPrimaryExpr(ctxt);
3499 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003500 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003501
3502 if (CUR != '[') return;
3503
3504 CHECK_TYPE(XPATH_NODESET);
3505
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003506 while (CUR == '[') {
3507 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003508 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003509 }
3510
3511
3512}
3513
3514/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003515 * xmlXPathScanName:
3516 * @ctxt: the XPath Parser context
3517 *
3518 * Trickery: parse an XML name but without consuming the input flow
3519 * Needed for rollback cases.
3520 *
3521 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3522 * CombiningChar | Extender
3523 *
3524 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3525 *
3526 * [6] Names ::= Name (S Name)*
3527 *
3528 * Returns the Name parsed or NULL
3529 */
3530
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003531xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003532xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003533 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003534 int len = 0;
3535
Daniel Veillard00fdf371999-10-08 09:40:39 +00003536 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003537 if (!IS_LETTER(CUR) && (CUR != '_') &&
3538 (CUR != ':')) {
3539 return(NULL);
3540 }
3541
3542 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3543 (NXT(len) == '.') || (NXT(len) == '-') ||
3544 (NXT(len) == '_') || (NXT(len) == ':') ||
3545 (IS_COMBINING(NXT(len))) ||
3546 (IS_EXTENDER(NXT(len)))) {
3547 buf[len] = NXT(len);
3548 len++;
3549 if (len >= XML_MAX_NAMELEN) {
3550 fprintf(stderr,
3551 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3552 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3553 (NXT(len) == '.') || (NXT(len) == '-') ||
3554 (NXT(len) == '_') || (NXT(len) == ':') ||
3555 (IS_COMBINING(NXT(len))) ||
3556 (IS_EXTENDER(NXT(len))))
3557 len++;
3558 break;
3559 }
3560 }
3561 return(xmlStrndup(buf, len));
3562}
3563
3564/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003565 * xmlXPathEvalPathExpr:
3566 * @ctxt: the XPath Parser context
3567 *
3568 * [19] PathExpr ::= LocationPath
3569 * | FilterExpr
3570 * | FilterExpr '/' RelativeLocationPath
3571 * | FilterExpr '//' RelativeLocationPath
3572 *
3573 * Parse and evaluate a path expression, then push the result on the stack
3574 * The / operator and // operators combine an arbitrary expression
3575 * and a relative location path. It is an error if the expression
3576 * does not evaluate to a node-set.
3577 * The / operator does composition in the same way as when / is
3578 * used in a location path. As in location paths, // is short for
3579 * /descendant-or-self::node()/.
3580 */
3581
3582void
3583xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3584 xmlNodeSetPtr newset = NULL;
3585
Daniel Veillard00fdf371999-10-08 09:40:39 +00003586 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003587 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3588 (CUR == '\'') || (CUR == '"')) {
3589 xmlXPathEvalFilterExpr(ctxt);
3590 CHECK_ERROR;
3591 if ((CUR == '/') && (NXT(1) == '/')) {
3592 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003593 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003594 if (ctxt->context->nodelist == NULL) {
3595 STRANGE
3596 xmlXPathRoot(ctxt);
3597 }
3598 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3599 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3600 if (ctxt->context->nodelist != NULL)
3601 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3602 ctxt->context->nodelist = newset;
3603 ctxt->context->node = NULL;
3604 xmlXPathEvalRelativeLocationPath(ctxt);
3605 } else if (CUR == '/') {
3606 xmlXPathEvalRelativeLocationPath(ctxt);
3607 }
3608 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003609 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003610 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003611
3612 name = xmlXPathScanName(ctxt);
3613 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3614 xmlXPathEvalLocationPath(ctxt);
3615 else
3616 xmlXPathEvalFilterExpr(ctxt);
3617 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003618 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003619 }
3620}
3621
3622/**
3623 * xmlXPathEvalUnionExpr:
3624 * @ctxt: the XPath Parser context
3625 *
3626 * [18] UnionExpr ::= PathExpr
3627 * | UnionExpr '|' PathExpr
3628 *
3629 * Parse and evaluate an union expression, then push the result on the stack
3630 */
3631
3632void
3633xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3634 xmlXPathEvalPathExpr(ctxt);
3635 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003636 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003637 if (CUR == '|') {
3638 xmlNodeSetPtr old = ctxt->context->nodelist;
3639
Daniel Veillard00fdf371999-10-08 09:40:39 +00003640 NEXT;
3641 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003642 xmlXPathEvalPathExpr(ctxt);
3643
3644 if (ctxt->context->nodelist == NULL)
3645 ctxt->context->nodelist = old;
3646 else {
3647 ctxt->context->nodelist =
3648 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3649 xmlXPathFreeNodeSet(old);
3650 }
3651 }
3652}
3653
3654/**
3655 * xmlXPathEvalUnaryExpr:
3656 * @ctxt: the XPath Parser context
3657 *
3658 * [27] UnaryExpr ::= UnionExpr
3659 * | '-' UnaryExpr
3660 *
3661 * Parse and evaluate an unary expression, then push the result on the stack
3662 */
3663
3664void
3665xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3666 int minus = 0;
3667
Daniel Veillard00fdf371999-10-08 09:40:39 +00003668 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003669 if (CUR == '-') {
3670 minus = 1;
3671 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003672 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003673 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003674 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003675 CHECK_ERROR;
3676 if (minus) {
3677 xmlXPathValueFlipSign(ctxt);
3678 }
3679}
3680
3681/**
3682 * xmlXPathEvalMultiplicativeExpr:
3683 * @ctxt: the XPath Parser context
3684 *
3685 * [26] MultiplicativeExpr ::= UnaryExpr
3686 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3687 * | MultiplicativeExpr 'div' UnaryExpr
3688 * | MultiplicativeExpr 'mod' UnaryExpr
3689 * [34] MultiplyOperator ::= '*'
3690 *
3691 * Parse and evaluate an Additive expression, then push the result on the stack
3692 */
3693
3694void
3695xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3696 xmlXPathEvalUnaryExpr(ctxt);
3697 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003698 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003699 while ((CUR == '*') ||
3700 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3701 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3702 int op = -1;
3703
3704 if (CUR == '*') {
3705 op = 0;
3706 NEXT;
3707 } else if (CUR == 'd') {
3708 op = 1;
3709 SKIP(3);
3710 } else if (CUR == 'm') {
3711 op = 2;
3712 SKIP(3);
3713 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003714 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003715 xmlXPathEvalUnaryExpr(ctxt);
3716 CHECK_ERROR;
3717 switch (op) {
3718 case 0:
3719 xmlXPathMultValues(ctxt);
3720 break;
3721 case 1:
3722 xmlXPathDivValues(ctxt);
3723 break;
3724 case 2:
3725 xmlXPathModValues(ctxt);
3726 break;
3727 }
3728 }
3729}
3730
3731/**
3732 * xmlXPathEvalAdditiveExpr:
3733 * @ctxt: the XPath Parser context
3734 *
3735 * [25] AdditiveExpr ::= MultiplicativeExpr
3736 * | AdditiveExpr '+' MultiplicativeExpr
3737 * | AdditiveExpr '-' MultiplicativeExpr
3738 *
3739 * Parse and evaluate an Additive expression, then push the result on the stack
3740 */
3741
3742void
3743xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3744 xmlXPathEvalMultiplicativeExpr(ctxt);
3745 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003746 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003747 while ((CUR == '+') || (CUR == '-')) {
3748 int plus;
3749
3750 if (CUR == '+') plus = 1;
3751 else plus = 0;
3752 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003753 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003754 xmlXPathEvalMultiplicativeExpr(ctxt);
3755 CHECK_ERROR;
3756 if (plus) xmlXPathAddValues(ctxt);
3757 else xmlXPathSubValues(ctxt);
3758 }
3759}
3760
3761/**
3762 * xmlXPathEvalRelationalExpr:
3763 * @ctxt: the XPath Parser context
3764 *
3765 * [24] RelationalExpr ::= AdditiveExpr
3766 * | RelationalExpr '<' AdditiveExpr
3767 * | RelationalExpr '>' AdditiveExpr
3768 * | RelationalExpr '<=' AdditiveExpr
3769 * | RelationalExpr '>=' AdditiveExpr
3770 *
3771 * A <= B > C is allowed ? Answer from James, yes with
3772 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3773 * which is basically what got implemented.
3774 *
3775 * Parse and evaluate a Relational expression, then push the result
3776 * on the stack
3777 */
3778
3779void
3780xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3781 xmlXPathEvalAdditiveExpr(ctxt);
3782 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003783 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003784 while ((CUR == '<') ||
3785 (CUR == '>') ||
3786 ((CUR == '<') && (NXT(1) == '=')) ||
3787 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003788 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003789
3790 if (CUR == '<') inf = 1;
3791 else inf = 0;
3792 if (NXT(1) == '=') strict = 0;
3793 else strict = 1;
3794 NEXT;
3795 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003796 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003797 xmlXPathEvalAdditiveExpr(ctxt);
3798 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003799 ret = xmlXPathCompareValues(ctxt, inf, strict);
3800 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003801 }
3802}
3803
3804/**
3805 * xmlXPathEvalEqualityExpr:
3806 * @ctxt: the XPath Parser context
3807 *
3808 * [23] EqualityExpr ::= RelationalExpr
3809 * | EqualityExpr '=' RelationalExpr
3810 * | EqualityExpr '!=' RelationalExpr
3811 *
3812 * A != B != C is allowed ? Answer from James, yes with
3813 * (RelationalExpr = RelationalExpr) = RelationalExpr
3814 * (RelationalExpr != RelationalExpr) != RelationalExpr
3815 * which is basically what got implemented.
3816 *
3817 * Parse and evaluate an Equality expression, then push the result on the stack
3818 *
3819 */
3820void
3821xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3822 xmlXPathEvalRelationalExpr(ctxt);
3823 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003824 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003825 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003826 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003827 int eq, equal;
3828
3829 if (CUR == '=') eq = 1;
3830 else eq = 0;
3831 NEXT;
3832 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003833 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003834 xmlXPathEvalRelationalExpr(ctxt);
3835 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003836 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003837 if (eq) res = xmlXPathNewBoolean(equal);
3838 else res = xmlXPathNewBoolean(!equal);
3839 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003840 }
3841}
3842
3843/**
3844 * xmlXPathEvalAndExpr:
3845 * @ctxt: the XPath Parser context
3846 *
3847 * [22] AndExpr ::= EqualityExpr
3848 * | AndExpr 'and' EqualityExpr
3849 *
3850 * Parse and evaluate an AND expression, then push the result on the stack
3851 *
3852 */
3853void
3854xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3855 xmlXPathEvalEqualityExpr(ctxt);
3856 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003857 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003858 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3859 xmlXPathObjectPtr arg1, arg2;
3860
3861 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003862 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003863 xmlXPathEvalEqualityExpr(ctxt);
3864 CHECK_ERROR;
3865 arg2 = valuePop(ctxt);
3866 arg1 = valuePop(ctxt);
3867 arg1->boolval &= arg2->boolval;
3868 valuePush(ctxt, arg1);
3869 xmlXPathFreeObject(arg2);
3870 }
3871}
3872
3873/**
3874 * xmlXPathEvalExpr:
3875 * @ctxt: the XPath Parser context
3876 *
3877 * [14] Expr ::= OrExpr
3878 * [21] OrExpr ::= AndExpr
3879 * | OrExpr 'or' AndExpr
3880 *
3881 * Parse and evaluate an expression, then push the result on the stack
3882 *
3883 */
3884void
3885xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3886 xmlXPathEvalAndExpr(ctxt);
3887 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003888 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003889 while ((CUR == 'o') && (NXT(1) == 'r')) {
3890 xmlXPathObjectPtr arg1, arg2;
3891
3892 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003893 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003894 xmlXPathEvalAndExpr(ctxt);
3895 CHECK_ERROR;
3896 arg2 = valuePop(ctxt);
3897 arg1 = valuePop(ctxt);
3898 arg1->boolval |= arg2->boolval;
3899 valuePush(ctxt, arg1);
3900 xmlXPathFreeObject(arg2);
3901 }
3902}
3903
3904/**
3905 * xmlXPathEvaluatePredicateResult:
3906 * @ctxt: the XPath Parser context
3907 * @res: the Predicate Expression evaluation result
3908 * @index: index of the current node in the current list
3909 *
3910 * Evaluate a predicate result for the current node.
3911 * A PredicateExpr is evaluated by evaluating the Expr and converting
3912 * the result to a boolean. If the result is a number, the result will
3913 * be converted to true if the number is equal to the position of the
3914 * context node in the context node list (as returned by the position
3915 * function) and will be converted to false otherwise; if the result
3916 * is not a number, then the result will be converted as if by a call
3917 * to the boolean function.
3918 */
3919int
3920xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3921 xmlXPathObjectPtr res, int index) {
3922 if (res == NULL) return(0);
3923 switch (res->type) {
3924 case XPATH_BOOLEAN:
3925 return(res->boolval);
3926 case XPATH_NUMBER:
3927 return(res->floatval == index);
3928 case XPATH_NODESET:
3929 return(res->nodesetval->nodeNr != 0);
3930 case XPATH_STRING:
3931 return((res->stringval != NULL) &&
3932 (xmlStrlen(res->stringval) != 0));
3933 default:
3934 STRANGE
3935 }
3936 return(0);
3937}
3938
3939/**
3940 * xmlXPathEvalPredicate:
3941 * @ctxt: the XPath Parser context
3942 *
3943 * [8] Predicate ::= '[' PredicateExpr ']'
3944 * [9] PredicateExpr ::= Expr
3945 *
3946 * Parse and evaluate a predicate for all the elements of the
3947 * current node list. Then refine the list by removing all
3948 * nodes where the predicate is false.
3949 */
3950void
3951xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003952 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003953 xmlXPathObjectPtr res;
3954 xmlNodeSetPtr newset = NULL;
3955 int i;
3956
Daniel Veillard00fdf371999-10-08 09:40:39 +00003957 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003958 if (CUR != '[') {
3959 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3960 }
3961 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003962 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003963 if ((ctxt->context->nodelist == NULL) ||
3964 (ctxt->context->nodelist->nodeNr == 0)) {
3965 ctxt->context->node = NULL;
3966 xmlXPathEvalExpr(ctxt);
3967 CHECK_ERROR;
3968 res = valuePop(ctxt);
3969 if (res != NULL)
3970 xmlXPathFreeObject(res);
3971 } else {
3972 cur = ctxt->cur;
3973 newset = xmlXPathNodeSetCreate(NULL);
3974 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3975 ctxt->cur = cur;
3976 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3977 xmlXPathEvalExpr(ctxt);
3978 CHECK_ERROR;
3979 res = valuePop(ctxt);
3980 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3981 xmlXPathNodeSetAdd(newset,
3982 ctxt->context->nodelist->nodeTab[i]);
3983 if (res != NULL)
3984 xmlXPathFreeObject(res);
3985 }
3986 if (ctxt->context->nodelist != NULL)
3987 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3988 ctxt->context->nodelist = newset;
3989 ctxt->context->node = NULL;
3990 }
3991 if (CUR != ']') {
3992 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3993 }
3994 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003995 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003996#ifdef DEBUG_STEP
3997 fprintf(xmlXPathDebug, "After predicate : ");
3998 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3999#endif
4000}
4001
4002/**
4003 * xmlXPathEvalBasis:
4004 * @ctxt: the XPath Parser context
4005 *
4006 * [5] Basis ::= AxisName '::' NodeTest
4007 * | AbbreviatedBasis
4008 * [13] AbbreviatedBasis ::= NodeTest
4009 * | '@' NodeTest
4010 * [7] NodeTest ::= WildcardName
4011 * | NodeType '(' ')'
4012 * | 'processing-instruction' '(' Literal ')'
4013 * [37] WildcardName ::= '*'
4014 * | NCName ':' '*'
4015 * | QName
4016 *
4017 * Evaluate one step in a Location Path
4018 */
4019void
4020xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004021 xmlChar *name = NULL;
4022 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004023 int type = 0;
4024 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4025 int nodetest = NODE_TEST_NONE;
4026 int nodetype = 0;
4027 xmlNodeSetPtr newset = NULL;
4028
4029 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004030 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004031 axis = AXIS_ATTRIBUTE;
4032 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004033 } else if (CUR == '*') {
4034 NEXT;
4035 nodetest = NODE_TEST_ALL;
4036 } else {
4037 name = xmlXPathParseNCName(ctxt);
4038 if (name == NULL) {
4039 ERROR(XPATH_EXPR_ERROR);
4040 }
4041 type = xmlXPathGetNameType(ctxt, name);
4042 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004043 case IS_FUNCTION: {
4044 xmlXPathFunction func;
4045 int nbargs = 0;
4046 xmlXPathObjectPtr top;
4047
4048 top = ctxt->value;
4049 func = xmlXPathIsFunction(ctxt, name);
4050 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004051 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004052 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4053 }
4054#ifdef DEBUG_EXPR
4055 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4056#endif
4057
4058 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004059 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004060 ERROR(XPATH_EXPR_ERROR);
4061 }
4062 NEXT;
4063
4064 while (CUR != ')') {
4065 xmlXPathEvalExpr(ctxt);
4066 nbargs++;
4067 if (CUR == ')') break;
4068 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004069 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004070 ERROR(XPATH_EXPR_ERROR);
4071 }
4072 NEXT;
4073 }
4074 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004075 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004076 func(ctxt, nbargs);
4077 if ((ctxt->value != top) &&
4078 (ctxt->value != NULL) &&
4079 (ctxt->value->type == XPATH_NODESET)) {
4080 xmlXPathObjectPtr cur;
4081
4082 cur = valuePop(ctxt);
4083 ctxt->context->nodelist = cur->nodesetval;
4084 ctxt->context->node = NULL;
4085 cur->nodesetval = NULL;
4086 xmlXPathFreeObject(cur);
4087 }
4088 return;
4089 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004090 /*
4091 * Simple case: no axis seach all given node types.
4092 */
4093 case NODE_TYPE_COMMENT:
4094 if ((CUR != '(') || (NXT(1) != ')')) break;
4095 SKIP(2);
4096 nodetest = NODE_TEST_TYPE;
4097 nodetype = XML_COMMENT_NODE;
4098 goto search_nodes;
4099 case NODE_TYPE_TEXT:
4100 if ((CUR != '(') || (NXT(1) != ')')) break;
4101 SKIP(2);
4102 nodetest = NODE_TEST_TYPE;
4103 nodetype = XML_TEXT_NODE;
4104 goto search_nodes;
4105 case NODE_TYPE_NODE:
4106 if ((CUR != '(') || (NXT(1) != ')')) {
4107 nodetest = NODE_TEST_NAME;
4108 break;
4109 }
4110 SKIP(2);
4111 nodetest = NODE_TEST_TYPE;
4112 nodetype = XML_ELEMENT_NODE;
4113 goto search_nodes;
4114 case NODE_TYPE_PI:
4115 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004116 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004117 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004118 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004119 xmlXPathObjectPtr cur;
4120
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004121 /*
4122 * Specific case: search a PI by name.
4123 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004124 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004125 nodetest = NODE_TEST_PI;
4126 xmlXPathEvalLiteral(ctxt);
4127 CHECK_ERROR;
4128 if (CUR != ')')
4129 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004130 NEXT;
4131 xmlXPathStringFunction(ctxt, 1);
4132 CHECK_ERROR;
4133 cur = valuePop(ctxt);
4134 name = xmlStrdup(cur->stringval);
4135 xmlXPathFreeObject(cur);
4136 } else
4137 SKIP(2);
4138 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004139 goto search_nodes;
4140
4141 /*
4142 * Handling of the compund form: got the axis.
4143 */
4144 case AXIS_ANCESTOR:
4145 case AXIS_ANCESTOR_OR_SELF:
4146 case AXIS_ATTRIBUTE:
4147 case AXIS_CHILD:
4148 case AXIS_DESCENDANT:
4149 case AXIS_DESCENDANT_OR_SELF:
4150 case AXIS_FOLLOWING:
4151 case AXIS_FOLLOWING_SIBLING:
4152 case AXIS_NAMESPACE:
4153 case AXIS_PARENT:
4154 case AXIS_PRECEDING:
4155 case AXIS_PRECEDING_SIBLING:
4156 case AXIS_SELF:
4157 if ((CUR != ':') || (NXT(1) != ':')) {
4158 nodetest = NODE_TEST_NAME;
4159 break;
4160 }
4161 SKIP(2);
4162 axis = type;
4163 break;
4164
4165 /*
4166 * Default: abbreviated syntax the axis is AXIS_CHILD
4167 */
4168 default:
4169 nodetest = NODE_TEST_NAME;
4170 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004171parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004172 if (nodetest == NODE_TEST_NONE) {
4173 if (CUR == '*') {
4174 NEXT;
4175 nodetest = NODE_TEST_ALL;
4176 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004177 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004178 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004179 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004180 if (name == NULL) {
4181 ERROR(XPATH_EXPR_ERROR);
4182 }
4183 type = xmlXPathGetNameType(ctxt, name);
4184 switch (type) {
4185 /*
4186 * Simple case: no axis seach all given node types.
4187 */
4188 case NODE_TYPE_COMMENT:
4189 if ((CUR != '(') || (NXT(1) != ')')) break;
4190 SKIP(2);
4191 nodetest = NODE_TEST_TYPE;
4192 nodetype = XML_COMMENT_NODE;
4193 goto search_nodes;
4194 case NODE_TYPE_TEXT:
4195 if ((CUR != '(') || (NXT(1) != ')')) break;
4196 SKIP(2);
4197 nodetest = NODE_TEST_TYPE;
4198 nodetype = XML_TEXT_NODE;
4199 goto search_nodes;
4200 case NODE_TYPE_NODE:
4201 if ((CUR != '(') || (NXT(1) != ')')) {
4202 nodetest = NODE_TEST_NAME;
4203 break;
4204 }
4205 SKIP(2);
4206 nodetest = NODE_TEST_TYPE;
4207 nodetype = XML_ELEMENT_NODE;
4208 goto search_nodes;
4209 case NODE_TYPE_PI:
4210 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004211 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004212 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004213 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004214 xmlXPathObjectPtr cur;
4215
Daniel Veillardb05deb71999-08-10 19:04:08 +00004216 /*
4217 * Specific case: search a PI by name.
4218 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004219 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004220 nodetest = NODE_TEST_PI;
4221 xmlXPathEvalLiteral(ctxt);
4222 CHECK_ERROR;
4223 if (CUR != ')')
4224 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004225 NEXT;
4226 xmlXPathStringFunction(ctxt, 1);
4227 CHECK_ERROR;
4228 cur = valuePop(ctxt);
4229 name = xmlStrdup(cur->stringval);
4230 xmlXPathFreeObject(cur);
4231 } else
4232 SKIP(2);
4233 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004234 goto search_nodes;
4235 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004236 nodetest = NODE_TEST_NAME;
4237 }
4238 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4239 NEXT;
4240 prefix = name;
4241 if (CUR == '*') {
4242 NEXT;
4243 nodetest = NODE_TEST_ALL;
4244 } else
4245 name = xmlXPathParseNCName(ctxt);
4246 } else if (name == NULL)
4247 ERROR(XPATH_EXPR_ERROR);
4248 }
4249
4250search_nodes:
4251
4252#ifdef DEBUG_STEP
4253 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4254#endif
4255 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4256 prefix, name);
4257 if (ctxt->context->nodelist != NULL)
4258 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4259 ctxt->context->nodelist = newset;
4260 ctxt->context->node = NULL;
4261#ifdef DEBUG_STEP
4262 fprintf(xmlXPathDebug, "Basis : ");
4263 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4264#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004265 if (name != NULL) xmlFree(name);
4266 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004267}
4268
4269/**
4270 * xmlXPathEvalStep:
4271 * @ctxt: the XPath Parser context
4272 *
4273 * [4] Step ::= Basis Predicate*
4274 * | AbbreviatedStep
4275 * [12] AbbreviatedStep ::= '.'
4276 * | '..'
4277 *
4278 * Evaluate one step in a Location Path
4279 * A location step of . is short for self::node(). This is
4280 * particularly useful in conjunction with //. For example, the
4281 * location path .//para is short for
4282 * self::node()/descendant-or-self::node()/child::para
4283 * and so will select all para descendant elements of the context
4284 * node.
4285 * Similarly, a location step of .. is short for parent::node().
4286 * For example, ../title is short for parent::node()/child::title
4287 * and so will select the title children of the parent of the context
4288 * node.
4289 */
4290void
4291xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4292 xmlNodeSetPtr newset = NULL;
4293
Daniel Veillard00fdf371999-10-08 09:40:39 +00004294 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004295 if ((CUR == '.') && (NXT(1) == '.')) {
4296 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004297 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004298 if (ctxt->context->nodelist == NULL) {
4299 STRANGE
4300 xmlXPathRoot(ctxt);
4301 }
4302 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4303 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4304 if (ctxt->context->nodelist != NULL)
4305 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4306 ctxt->context->nodelist = newset;
4307 ctxt->context->node = NULL;
4308 } else if (CUR == '.') {
4309 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004310 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004311 } else {
4312 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004313 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004314 while (CUR == '[') {
4315 xmlXPathEvalPredicate(ctxt);
4316 }
4317 }
4318#ifdef DEBUG_STEP
4319 fprintf(xmlXPathDebug, "Step : ");
4320 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4321#endif
4322}
4323
4324/**
4325 * xmlXPathEvalRelativeLocationPath:
4326 * @ctxt: the XPath Parser context
4327 *
4328 * [3] RelativeLocationPath ::= Step
4329 * | RelativeLocationPath '/' Step
4330 * | AbbreviatedRelativeLocationPath
4331 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4332 *
4333 */
4334void
4335xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4336 xmlNodeSetPtr newset = NULL;
4337
Daniel Veillard00fdf371999-10-08 09:40:39 +00004338 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004339 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004340 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004341 while (CUR == '/') {
4342 if ((CUR == '/') && (NXT(1) == '/')) {
4343 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004344 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004345 if (ctxt->context->nodelist == NULL) {
4346 STRANGE
4347 xmlXPathRoot(ctxt);
4348 }
4349 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4350 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4351 if (ctxt->context->nodelist != NULL)
4352 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4353 ctxt->context->nodelist = newset;
4354 ctxt->context->node = NULL;
4355 xmlXPathEvalStep(ctxt);
4356 } else if (CUR == '/') {
4357 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004358 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004359 xmlXPathEvalStep(ctxt);
4360 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004361 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004362 }
4363}
4364
4365/**
4366 * xmlXPathEvalLocationPath:
4367 * @ctxt: the XPath Parser context
4368 *
4369 * [1] LocationPath ::= RelativeLocationPath
4370 * | AbsoluteLocationPath
4371 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4372 * | AbbreviatedAbsoluteLocationPath
4373 * [10] AbbreviatedAbsoluteLocationPath ::=
4374 * '//' RelativeLocationPath
4375 *
4376 * // is short for /descendant-or-self::node()/. For example,
4377 * //para is short for /descendant-or-self::node()/child::para and
4378 * so will select any para element in the document (even a para element
4379 * that is a document element will be selected by //para since the
4380 * document element node is a child of the root node); div//para is
4381 * short for div/descendant-or-self::node()/child::para and so will
4382 * select all para descendants of div children.
4383 */
4384void
4385xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4386 xmlNodeSetPtr newset = NULL;
4387
Daniel Veillard00fdf371999-10-08 09:40:39 +00004388 SKIP_BLANKS;
4389 if (CUR != '/') {
4390 xmlXPathEvalRelativeLocationPath(ctxt);
4391 } else {
4392 while (CUR == '/') {
4393 if ((CUR == '/') && (NXT(1) == '/')) {
4394 SKIP(2);
4395 SKIP_BLANKS;
4396 if (ctxt->context->nodelist == NULL)
4397 xmlXPathRoot(ctxt);
4398 newset = xmlXPathNodeCollectAndTest(ctxt,
4399 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4400 XML_ELEMENT_NODE, NULL, NULL);
4401 if (ctxt->context->nodelist != NULL)
4402 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4403 ctxt->context->nodelist = newset;
4404 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004405 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004406 } else if (CUR == '/') {
4407 NEXT;
4408 SKIP_BLANKS;
4409 xmlXPathRoot(ctxt);
4410 if (CUR != 0)
4411 xmlXPathEvalRelativeLocationPath(ctxt);
4412 } else {
4413 xmlXPathEvalRelativeLocationPath(ctxt);
4414 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004415 }
4416 }
4417}
4418
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004419/**
4420 * xmlXPathEval:
4421 * @str: the XPath expression
4422 * @ctxt: the XPath context
4423 *
4424 * Evaluate the XPath Location Path in the given context.
4425 *
4426 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4427 * the caller has to free the object.
4428 */
4429xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004430xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004431 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004432 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004433 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004434
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004435 xmlXPathInit();
4436
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004437 CHECK_CONTEXT
4438
4439 if (xmlXPathDebug == NULL)
4440 xmlXPathDebug = stderr;
4441 pctxt = xmlXPathNewParserContext(str, ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004442 if (str[0] == '/')
4443 xmlXPathRoot(pctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004444 xmlXPathEvalLocationPath(pctxt);
4445
Daniel Veillardb96e6431999-08-29 21:02:19 +00004446 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004447 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004448 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004449 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004450 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004451 stack++;
4452 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004453 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004454 if (stack != 0) {
4455 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4456 stack);
4457 }
4458 if (pctxt->error == XPATH_EXPRESSION_OK)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004459 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004460 else
4461 res = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004462 xmlXPathFreeParserContext(pctxt);
4463 return(res);
4464}
4465
4466/**
4467 * xmlXPathEvalExpression:
4468 * @str: the XPath expression
4469 * @ctxt: the XPath context
4470 *
4471 * Evaluate the XPath expression in the given context.
4472 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004473 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004474 * the caller has to free the object.
4475 */
4476xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004477xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004478 xmlXPathParserContextPtr pctxt;
4479 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004480 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004481
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004482 xmlXPathInit();
4483
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004484 CHECK_CONTEXT
4485
4486 if (xmlXPathDebug == NULL)
4487 xmlXPathDebug = stderr;
4488 pctxt = xmlXPathNewParserContext(str, ctxt);
4489 xmlXPathEvalExpr(pctxt);
4490
4491 res = valuePop(pctxt);
4492 do {
4493 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004494 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004495 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004496 stack++;
4497 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004498 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004499 if (stack != 0) {
4500 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4501 stack);
4502 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004503 xmlXPathFreeParserContext(pctxt);
4504 return(res);
4505}
4506