blob: c5ce36af7132cf21b202f2b65a9f10f6e2f66cfd [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
50/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000051 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000052 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000053 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000054double xmlXPathNAN = 0;
55double xmlXPathPINF = 1;
56double xmlXPathMINF = -1;
57
Daniel Veillardb05deb71999-08-10 19:04:08 +000058#ifndef isinf
59#ifndef HAVE_ISINF
60
61#if HAVE_FPCLASS
62
63int isinf(double d) {
64 fpclass_t type = fpclass(d);
65 switch (type) {
66 case FP_NINF:
67 return(-1);
68 case FP_PINF:
69 return(1);
70 default:
71 return(0);
72 }
73 return(0);
74}
75
76#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
77
78#if HAVE_FP_CLASS_H
79#include <fp_class.h>
80#endif
81
82int isinf(double d) {
83#if HAVE_FP_CLASS
84 int fpclass = fp_class(d);
85#else
86 int fpclass = fp_class_d(d);
87#endif
88 if (fpclass == FP_POS_INF)
89 return(1);
90 if (fpclass == FP_NEG_INF)
91 return(-1);
92 return(0);
93}
94
95#elif defined(HAVE_CLASS)
96
97int isinf(double d) {
98 int fpclass = class(d);
99 if (fpclass == FP_PLUS_INF)
100 return(1);
101 if (fpclass == FP_MINUS_INF)
102 return(-1);
103 return(0);
104}
105#elif defined(finite) || defined(HAVE_FINITE)
106int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000107#elif defined(HUGE_VAL)
108static int isinf(double x)
109{
110 if (x == HUGE_VAL)
111 return(1);
112 if (x == -HUGE_VAL)
113 return(-1);
114 return(0);
115}
116#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000117
118#endif /* ! HAVE_ISINF */
119#endif /* ! defined(isinf) */
120
121#ifndef isnan
122#ifndef HAVE_ISNAN
123
124#ifdef HAVE_ISNAND
125#define isnan(f) isnand(f)
126#endif /* HAVE_iSNAND */
127
128#endif /* ! HAVE_iSNAN */
129#endif /* ! defined(isnan) */
130
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000131/**
132 * xmlXPathInit:
133 *
134 * Initialize the XPath environment
135 */
136void
137xmlXPathInit(void) {
138 static int initialized = 0;
139
140 if (initialized) return;
141
142 xmlXPathNAN = 0;
143 xmlXPathNAN /= 0;
144
145 xmlXPathPINF = 1;
146 xmlXPathPINF /= 0;
147
148 xmlXPathMINF = -1;
149 xmlXPathMINF /= 0;
150
151 initialized = 1;
152}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000153
154/* #define DEBUG */
155/* #define DEBUG_STEP */
156/* #define DEBUG_EXPR */
157
158FILE *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/**
751 * xmlXPathFreeObject:
752 * @obj: the object to free
753 *
754 * Free up an xmlXPathObjectPtr object.
755 */
756void
757xmlXPathFreeObject(xmlXPathObjectPtr obj) {
758 if (obj == NULL) return;
759 if (obj->nodesetval != NULL)
760 xmlXPathFreeNodeSet(obj->nodesetval);
761 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000762 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000763#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000764 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000765#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000766 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000767}
768
769/************************************************************************
770 * *
771 * Routines to handle XPath contexts *
772 * *
773 ************************************************************************/
774
775/**
776 * xmlXPathNewContext:
777 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000778 *
779 * Create a new xmlXPathContext
780 *
781 * Returns the xmlXPathContext just allocated.
782 */
783xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000784xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000785 xmlXPathContextPtr ret;
786
Daniel Veillard6454aec1999-09-02 22:04:43 +0000787 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000788 if (ret == NULL) {
789 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
790 return(NULL);
791 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000792 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000793 ret->doc = doc;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000794
795 ret->nb_variables = 0;
796 ret->max_variables = 0;
797 ret->variables = NULL;
798
799 ret->nb_types = 0;
800 ret->max_types = 0;
801 ret->types = NULL;
802
803 ret->nb_funcs = 0;
804 ret->max_funcs = 0;
805 ret->funcs = NULL;
806
807 ret->nb_axis = 0;
808 ret->max_axis = 0;
809 ret->axis = NULL;
810
Daniel Veillardb96e6431999-08-29 21:02:19 +0000811 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000812 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000813 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000814 return(ret);
815}
816
817/**
818 * xmlXPathFreeContext:
819 * @ctxt: the context to free
820 *
821 * Free up an xmlXPathContext
822 */
823void
824xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000825 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000826 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000827
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000828#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000829 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000830#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000831 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000832}
833
834/************************************************************************
835 * *
836 * Routines to handle XPath parser contexts *
837 * *
838 ************************************************************************/
839
840#define CHECK_CTXT \
841 if (ctxt == NULL) { \
842 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
843 __FILE__, __LINE__); \
844 } \
845
846
847#define CHECK_CONTEXT \
848 if (ctxt == NULL) { \
849 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
850 __FILE__, __LINE__); \
851 } \
852 if (ctxt->doc == NULL) { \
853 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
854 __FILE__, __LINE__); \
855 } \
856 if (ctxt->doc->root == NULL) { \
857 fprintf(xmlXPathDebug, \
858 "%s:%d Internal error: document without root\n", \
859 __FILE__, __LINE__); \
860 } \
861
862
863/**
864 * xmlXPathNewParserContext:
865 * @str: the XPath expression
866 * @ctxt: the XPath context
867 *
868 * Create a new xmlXPathParserContext
869 *
870 * Returns the xmlXPathParserContext just allocated.
871 */
872xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000873xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000874 xmlXPathParserContextPtr ret;
875
Daniel Veillard6454aec1999-09-02 22:04:43 +0000876 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000877 if (ret == NULL) {
878 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
879 return(NULL);
880 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000881 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000882 ret->cur = ret->base = str;
883 ret->context = ctxt;
884
885 /* Allocate the value stack */
886 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000887 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000888 ret->valueNr = 0;
889 ret->valueMax = 10;
890 ret->value = NULL;
891 return(ret);
892}
893
894/**
895 * xmlXPathFreeParserContext:
896 * @ctxt: the context to free
897 *
898 * Free up an xmlXPathParserContext
899 */
900void
901xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
902 if (ctxt->valueTab != NULL) {
903#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000904 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000905#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000906 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000907 }
908#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000909 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000910#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000911 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000912}
913
914/************************************************************************
915 * *
916 * The implicit core function library *
917 * *
918 ************************************************************************/
919
920/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000921 * Auto-pop and cast to a number
922 */
923void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
924
925#define CHECK_ARITY(x) \
926 if (nargs != (x)) { \
927 ERROR(XPATH_INVALID_ARITY); \
928 } \
929
930
931#define POP_FLOAT \
932 arg = valuePop(ctxt); \
933 if (arg == NULL) { \
934 ERROR(XPATH_INVALID_OPERAND); \
935 } \
936 if (arg->type != XPATH_NUMBER) { \
937 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000938 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000939 arg = valuePop(ctxt); \
940 }
941
942/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000943 * xmlXPathEqualNodeSetString
944 * @arg: the nodeset object argument
945 * @str: the string to compare to.
946 *
947 * Implement the equal operation on XPath objects content: @arg1 == @arg2
948 * If one object to be compared is a node-set and the other is a string,
949 * then the comparison will be true if and only if there is a node in
950 * the node-set such that the result of performing the comparison on the
951 * string-value of the node and the other string is true.
952 *
953 * Returns 0 or 1 depending on the results of the test.
954 */
955int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000956xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000957 int i;
958 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000959 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000960
961 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
962 return(0);
963 ns = arg->nodesetval;
964 for (i = 0;i < ns->nodeNr;i++) {
965 str2 = xmlNodeGetContent(ns->nodeTab[i]);
966 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000967 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000968 return(1);
969 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000970 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000971 }
972 return(0);
973}
974
975/**
976 * xmlXPathEqualNodeSetFloat
977 * @arg: the nodeset object argument
978 * @f: the float to compare to
979 *
980 * Implement the equal operation on XPath objects content: @arg1 == @arg2
981 * If one object to be compared is a node-set and the other is a number,
982 * then the comparison will be true if and only if there is a node in
983 * the node-set such that the result of performing the comparison on the
984 * number to be compared and on the result of converting the string-value
985 * of that node to a number using the number function is true.
986 *
987 * Returns 0 or 1 depending on the results of the test.
988 */
989int
990xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000991 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +0000992
993 if ((arg == NULL) || (arg->type != XPATH_NODESET))
994 return(0);
995
996 if (isnan(f))
997 sprintf(buf, "NaN");
998 else if (isinf(f) > 0)
999 sprintf(buf, "+Infinity");
1000 else if (isinf(f) < 0)
1001 sprintf(buf, "-Infinity");
1002 else
1003 sprintf(buf, "%0g", f);
1004
Daniel Veillardb96e6431999-08-29 21:02:19 +00001005 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001006}
1007
1008
1009/**
1010 * xmlXPathEqualNodeSets
1011 * @arg1: first nodeset object argument
1012 * @arg2: second nodeset object argument
1013 *
1014 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1015 * If both objects to be compared are node-sets, then the comparison
1016 * will be true if and only if there is a node in the first node-set and
1017 * a node in the second node-set such that the result of performing the
1018 * comparison on the string-values of the two nodes is true.
1019 *
1020 * (needless to say, this is a costly operation)
1021 *
1022 * Returns 0 or 1 depending on the results of the test.
1023 */
1024int
1025xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1026 int i;
1027 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001028 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001029
1030 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1031 return(0);
1032 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1033 return(0);
1034
1035 ns = arg1->nodesetval;
1036 for (i = 0;i < ns->nodeNr;i++) {
1037 str = xmlNodeGetContent(ns->nodeTab[i]);
1038 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001039 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001040 return(1);
1041 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001042 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001043 }
1044 return(0);
1045}
1046
1047/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001048 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001049 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001050 *
1051 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1052 *
1053 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001054 */
1055int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001056xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1057 xmlXPathObjectPtr arg1, arg2;
1058 int ret = 0;
1059
1060 arg1 = valuePop(ctxt);
1061 if (arg1 == NULL)
1062 ERROR0(XPATH_INVALID_OPERAND);
1063
1064 arg2 = valuePop(ctxt);
1065 if (arg2 == NULL) {
1066 xmlXPathFreeObject(arg1);
1067 ERROR0(XPATH_INVALID_OPERAND);
1068 }
1069
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001070 if (arg1 == arg2) {
1071#ifdef DEBUG_EXPR
1072 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1073#endif
1074 return(1);
1075 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001076
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001077 switch (arg1->type) {
1078 case XPATH_UNDEFINED:
1079#ifdef DEBUG_EXPR
1080 fprintf(xmlXPathDebug, "Equal: undefined\n");
1081#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001082 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001083 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001084 switch (arg2->type) {
1085 case XPATH_UNDEFINED:
1086#ifdef DEBUG_EXPR
1087 fprintf(xmlXPathDebug, "Equal: undefined\n");
1088#endif
1089 break;
1090 case XPATH_NODESET:
1091 ret = xmlXPathEqualNodeSets(arg1, arg2);
1092 break;
1093 case XPATH_BOOLEAN:
1094 if ((arg1->nodesetval == NULL) ||
1095 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1096 else
1097 ret = 1;
1098 ret = (ret == arg2->boolval);
1099 break;
1100 case XPATH_NUMBER:
1101 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1102 break;
1103 case XPATH_STRING:
1104 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1105 break;
1106 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001107 break;
1108 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001109 switch (arg2->type) {
1110 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001111#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001112 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001113#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001114 break;
1115 case XPATH_NODESET:
1116 if ((arg2->nodesetval == NULL) ||
1117 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1118 else
1119 ret = 1;
1120 break;
1121 case XPATH_BOOLEAN:
1122#ifdef DEBUG_EXPR
1123 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1124 arg1->boolval, arg2->boolval);
1125#endif
1126 ret = (arg1->boolval == arg2->boolval);
1127 break;
1128 case XPATH_NUMBER:
1129 if (arg2->floatval) ret = 1;
1130 else ret = 0;
1131 ret = (arg1->boolval == ret);
1132 break;
1133 case XPATH_STRING:
1134 if ((arg2->stringval == NULL) ||
1135 (arg2->stringval[0] == 0)) ret = 0;
1136 else
1137 ret = 1;
1138 ret = (arg1->boolval == ret);
1139 break;
1140 }
1141 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001142 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001143 switch (arg2->type) {
1144 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001145#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001146 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001147#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001148 break;
1149 case XPATH_NODESET:
1150 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1151 break;
1152 case XPATH_BOOLEAN:
1153 if (arg1->floatval) ret = 1;
1154 else ret = 0;
1155 ret = (arg2->boolval == ret);
1156 break;
1157 case XPATH_STRING:
1158 valuePush(ctxt, arg2);
1159 xmlXPathNumberFunction(ctxt, 1);
1160 arg2 = valuePop(ctxt);
1161 /* no break on purpose */
1162 case XPATH_NUMBER:
1163 ret = (arg1->floatval == arg2->floatval);
1164 break;
1165 }
1166 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001167 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001168 switch (arg2->type) {
1169 case XPATH_UNDEFINED:
1170#ifdef DEBUG_EXPR
1171 fprintf(xmlXPathDebug, "Equal: undefined\n");
1172#endif
1173 break;
1174 case XPATH_NODESET:
1175 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1176 break;
1177 case XPATH_BOOLEAN:
1178 if ((arg1->stringval == NULL) ||
1179 (arg1->stringval[0] == 0)) ret = 0;
1180 else
1181 ret = 1;
1182 ret = (arg2->boolval == ret);
1183 break;
1184 case XPATH_STRING:
1185 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1186 break;
1187 case XPATH_NUMBER:
1188 valuePush(ctxt, arg1);
1189 xmlXPathNumberFunction(ctxt, 1);
1190 arg1 = valuePop(ctxt);
1191 ret = (arg1->floatval == arg2->floatval);
1192 break;
1193 }
1194 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001195#ifdef DEBUG_EXPR
1196 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
1197 arg1->stringval, arg2->stringval);
1198#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001199 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001200 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001201 xmlXPathFreeObject(arg1);
1202 xmlXPathFreeObject(arg2);
1203 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001204}
1205
1206/**
1207 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001208 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001209 * @inf: less than (1) or greater than (2)
1210 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001211 *
1212 * Implement the compare operation on XPath objects:
1213 * @arg1 < @arg2 (1, 1, ...
1214 * @arg1 <= @arg2 (1, 0, ...
1215 * @arg1 > @arg2 (0, 1, ...
1216 * @arg1 >= @arg2 (0, 0, ...
1217 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001218 * When neither object to be compared is a node-set and the operator is
1219 * <=, <, >=, >, then the objects are compared by converted both objects
1220 * to numbers and comparing the numbers according to IEEE 754. The <
1221 * comparison will be true if and only if the first number is less than the
1222 * second number. The <= comparison will be true if and only if the first
1223 * number is less than or equal to the second number. The > comparison
1224 * will be true if and only if the first number is greater than the second
1225 * number. The >= comparison will be true if and only if the first number
1226 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001227 */
1228int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001229xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1230 int ret = 0;
1231 xmlXPathObjectPtr arg1, arg2;
1232
1233 arg2 = valuePop(ctxt);
1234 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1235 if (arg2 != NULL)
1236 xmlXPathFreeObject(arg2);
1237 ERROR0(XPATH_INVALID_OPERAND);
1238 }
1239
1240 arg1 = valuePop(ctxt);
1241 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1242 if (arg1 != NULL)
1243 xmlXPathFreeObject(arg1);
1244 xmlXPathFreeObject(arg2);
1245 ERROR0(XPATH_INVALID_OPERAND);
1246 }
1247
1248 if (arg1->type != XPATH_NUMBER) {
1249 valuePush(ctxt, arg1);
1250 xmlXPathNumberFunction(ctxt, 1);
1251 arg1 = valuePop(ctxt);
1252 }
1253 if (arg1->type != XPATH_NUMBER) {
1254 xmlXPathFreeObject(arg1);
1255 xmlXPathFreeObject(arg2);
1256 ERROR0(XPATH_INVALID_OPERAND);
1257 }
1258 if (arg2->type != XPATH_NUMBER) {
1259 valuePush(ctxt, arg2);
1260 xmlXPathNumberFunction(ctxt, 1);
1261 arg2 = valuePop(ctxt);
1262 }
1263 if (arg2->type != XPATH_NUMBER) {
1264 xmlXPathFreeObject(arg1);
1265 xmlXPathFreeObject(arg2);
1266 ERROR0(XPATH_INVALID_OPERAND);
1267 }
1268 /*
1269 * Add tests for infinity and nan
1270 * => feedback on 3.4 for Inf and NaN
1271 */
1272 if (inf && strict)
1273 ret = (arg1->floatval < arg2->floatval);
1274 else if (inf && !strict)
1275 ret = (arg1->floatval <= arg2->floatval);
1276 else if (!inf && strict)
1277 ret = (arg1->floatval > arg2->floatval);
1278 else if (!inf && !strict)
1279 ret = (arg1->floatval >= arg2->floatval);
1280 xmlXPathFreeObject(arg1);
1281 xmlXPathFreeObject(arg2);
1282 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001283}
1284
1285/**
1286 * xmlXPathValueFlipSign:
1287 * @ctxt: the XPath Parser context
1288 *
1289 * Implement the unary - operation on an XPath object
1290 * The numeric operators convert their operands to numbers as if
1291 * by calling the number function.
1292 */
1293void
1294xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1295 xmlXPathObjectPtr arg;
1296
1297 POP_FLOAT
1298 arg->floatval = -arg->floatval;
1299 valuePush(ctxt, arg);
1300}
1301
1302/**
1303 * xmlXPathAddValues:
1304 * @ctxt: the XPath Parser context
1305 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001306 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001307 * The numeric operators convert their operands to numbers as if
1308 * by calling the number function.
1309 */
1310void
1311xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1312 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001313 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001314
1315 POP_FLOAT
1316 val = arg->floatval;
1317 xmlXPathFreeObject(arg);
1318
1319 POP_FLOAT
1320 arg->floatval += val;
1321 valuePush(ctxt, arg);
1322}
1323
1324/**
1325 * xmlXPathSubValues:
1326 * @ctxt: the XPath Parser context
1327 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001328 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001329 * The numeric operators convert their operands to numbers as if
1330 * by calling the number function.
1331 */
1332void
1333xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1334 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001335 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001336
1337 POP_FLOAT
1338 val = arg->floatval;
1339 xmlXPathFreeObject(arg);
1340
1341 POP_FLOAT
1342 arg->floatval -= val;
1343 valuePush(ctxt, arg);
1344}
1345
1346/**
1347 * xmlXPathMultValues:
1348 * @ctxt: the XPath Parser context
1349 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001350 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001351 * The numeric operators convert their operands to numbers as if
1352 * by calling the number function.
1353 */
1354void
1355xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1356 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001357 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001358
1359 POP_FLOAT
1360 val = arg->floatval;
1361 xmlXPathFreeObject(arg);
1362
1363 POP_FLOAT
1364 arg->floatval *= val;
1365 valuePush(ctxt, arg);
1366}
1367
1368/**
1369 * xmlXPathDivValues:
1370 * @ctxt: the XPath Parser context
1371 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001372 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001373 * The numeric operators convert their operands to numbers as if
1374 * by calling the number function.
1375 */
1376void
1377xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1378 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001379 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001380
1381 POP_FLOAT
1382 val = arg->floatval;
1383 xmlXPathFreeObject(arg);
1384
1385 POP_FLOAT
1386 arg->floatval /= val;
1387 valuePush(ctxt, arg);
1388}
1389
1390/**
1391 * xmlXPathModValues:
1392 * @ctxt: the XPath Parser context
1393 *
1394 * Implement the div operation on XPath objects: @arg1 / @arg2
1395 * The numeric operators convert their operands to numbers as if
1396 * by calling the number function.
1397 */
1398void
1399xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1400 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001401 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001402
1403 POP_FLOAT
1404 val = arg->floatval;
1405 xmlXPathFreeObject(arg);
1406
1407 POP_FLOAT
1408 arg->floatval /= val;
1409 valuePush(ctxt, arg);
1410}
1411
1412/************************************************************************
1413 * *
1414 * The traversal functions *
1415 * *
1416 ************************************************************************/
1417
1418#define AXIS_ANCESTOR 1
1419#define AXIS_ANCESTOR_OR_SELF 2
1420#define AXIS_ATTRIBUTE 3
1421#define AXIS_CHILD 4
1422#define AXIS_DESCENDANT 5
1423#define AXIS_DESCENDANT_OR_SELF 6
1424#define AXIS_FOLLOWING 7
1425#define AXIS_FOLLOWING_SIBLING 8
1426#define AXIS_NAMESPACE 9
1427#define AXIS_PARENT 10
1428#define AXIS_PRECEDING 11
1429#define AXIS_PRECEDING_SIBLING 12
1430#define AXIS_SELF 13
1431
1432/*
1433 * A traversal function enumerates nodes along an axis.
1434 * Initially it must be called with NULL, and it indicates
1435 * termination on the axis by returning NULL.
1436 */
1437typedef xmlNodePtr (*xmlXPathTraversalFunction)
1438 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1439
1440/**
1441 * mlXPathNextSelf:
1442 * @ctxt: the XPath Parser context
1443 * @cur: the current node in the traversal
1444 *
1445 * Traversal function for the "self" direction
1446 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001447 *
1448 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001449 */
1450xmlNodePtr
1451xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1452 if (cur == NULL)
1453 return(ctxt->context->node);
1454 return(NULL);
1455}
1456
1457/**
1458 * mlXPathNextChild:
1459 * @ctxt: the XPath Parser context
1460 * @cur: the current node in the traversal
1461 *
1462 * Traversal function for the "child" direction
1463 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001464 *
1465 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001466 */
1467xmlNodePtr
1468xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001469 if (cur == NULL) {
1470 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1471 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001472 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001473 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +00001474 if ((ctxt->context->node->type == XML_DOCUMENT_NODE) ||
1475 (ctxt->context->node->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001476 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001477 return(cur->next);
1478}
1479
1480/**
1481 * mlXPathNextDescendant:
1482 * @ctxt: the XPath Parser context
1483 * @cur: the current node in the traversal
1484 *
1485 * Traversal function for the "descendant" direction
1486 * the descendant axis contains the descendants of the context node in document
1487 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001488 *
1489 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001490 */
1491xmlNodePtr
1492xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001493 if (cur == NULL) {
1494 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1495 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001496 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001497 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001498
1499 if (cur->childs != NULL) return(cur->childs);
1500 if (cur->next != NULL) return(cur->next);
1501
1502 do {
1503 cur = cur->parent;
1504 if (cur == NULL) return(NULL);
1505 if (cur == ctxt->context->node) return(NULL);
1506 if (cur->next != NULL) {
1507 cur = cur->next;
1508 return(cur);
1509 }
1510 } while (cur != NULL);
1511 return(cur);
1512}
1513
1514/**
1515 * mlXPathNextDescendantOrSelf:
1516 * @ctxt: the XPath Parser context
1517 * @cur: the current node in the traversal
1518 *
1519 * Traversal function for the "descendant-or-self" direction
1520 * the descendant-or-self axis contains the context node and the descendants
1521 * of the context node in document order; thus the context node is the first
1522 * node on the axis, and the first child of the context node is the second node
1523 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001524 *
1525 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001526 */
1527xmlNodePtr
1528xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1529 if (cur == NULL)
1530 return(ctxt->context->node);
1531
Daniel Veillardb05deb71999-08-10 19:04:08 +00001532 if (cur == (xmlNodePtr) ctxt->context->doc)
1533 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001534 if (cur->childs != NULL) return(cur->childs);
1535 if (cur->next != NULL) return(cur->next);
1536
1537 do {
1538 cur = cur->parent;
1539 if (cur == NULL) return(NULL);
1540 if (cur == ctxt->context->node) return(NULL);
1541 if (cur->next != NULL) {
1542 cur = cur->next;
1543 return(cur);
1544 }
1545 } while (cur != NULL);
1546 return(cur);
1547}
1548
1549/**
1550 * xmlXPathNextParent:
1551 * @ctxt: the XPath Parser context
1552 * @cur: the current node in the traversal
1553 *
1554 * Traversal function for the "parent" direction
1555 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001556 *
1557 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001558 */
1559xmlNodePtr
1560xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1561 /*
1562 * !!!!!!!!!!!!!
1563 * the parent of an attribute or namespace node is the element
1564 * to which the attribute or namespace node is attached
1565 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001566 if (cur == NULL) {
1567 if (ctxt->context->node->parent == NULL)
1568 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001569 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001570 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001571 return(NULL);
1572}
1573
1574/**
1575 * xmlXPathNextAncestor:
1576 * @ctxt: the XPath Parser context
1577 * @cur: the current node in the traversal
1578 *
1579 * Traversal function for the "ancestor" direction
1580 * the ancestor axis contains the ancestors of the context node; the ancestors
1581 * of the context node consist of the parent of context node and the parent's
1582 * parent and so on; the nodes are ordered in reverse document order; thus the
1583 * parent is the first node on the axis, and the parent's parent is the second
1584 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001585 *
1586 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001587 */
1588xmlNodePtr
1589xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1590 /*
1591 * !!!!!!!!!!!!!
1592 * the parent of an attribute or namespace node is the element
1593 * to which the attribute or namespace node is attached
1594 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001595 if (cur == NULL) {
1596 if (ctxt->context->node->parent == NULL)
1597 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001598 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001599 }
1600 if (cur == ctxt->context->doc->root)
1601 return((xmlNodePtr) ctxt->context->doc);
1602 if (cur == (xmlNodePtr) ctxt->context->doc)
1603 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001604 return(cur->parent);
1605}
1606
1607/**
1608 * xmlXPathNextAncestorOrSelf:
1609 * @ctxt: the XPath Parser context
1610 * @cur: the current node in the traversal
1611 *
1612 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001613 * he ancestor-or-self axis contains the context node and ancestors of
1614 * the context node in reverse document order; thus the context node is
1615 * the first node on the axis, and the context node's parent the second;
1616 * parent here is defined the same as with the parent axis.
1617 *
1618 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001619 */
1620xmlNodePtr
1621xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1622 /*
1623 * !!!!!!!!!!!!!
1624 * the parent of an attribute or namespace node is the element
1625 * to which the attribute or namespace node is attached
1626 */
1627 if (cur == NULL)
1628 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001629 if (cur == ctxt->context->doc->root)
1630 return((xmlNodePtr) ctxt->context->doc);
1631 if (cur == (xmlNodePtr) ctxt->context->doc)
1632 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001633 return(cur->parent);
1634}
1635
1636/**
1637 * xmlXPathNextFollowingSibling:
1638 * @ctxt: the XPath Parser context
1639 * @cur: the current node in the traversal
1640 *
1641 * Traversal function for the "following-sibling" direction
1642 * The following-sibling axis contains the following siblings of the context
1643 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001644 *
1645 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001646 */
1647xmlNodePtr
1648xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001649 if (cur == (xmlNodePtr) ctxt->context->doc)
1650 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001651 if (cur == NULL)
1652 return(ctxt->context->node->next);
1653 return(cur->next);
1654}
1655
1656/**
1657 * xmlXPathNextPrecedingSibling:
1658 * @ctxt: the XPath Parser context
1659 * @cur: the current node in the traversal
1660 *
1661 * Traversal function for the "preceding-sibling" direction
1662 * The preceding-sibling axis contains the preceding siblings of the context
1663 * node in reverse document order; the first preceding sibling is first on the
1664 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001665 *
1666 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001667 */
1668xmlNodePtr
1669xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001670 if (cur == (xmlNodePtr) ctxt->context->doc)
1671 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001672 if (cur == NULL)
1673 return(ctxt->context->node->prev);
1674 return(cur->prev);
1675}
1676
1677/**
1678 * xmlXPathNextFollowing:
1679 * @ctxt: the XPath Parser context
1680 * @cur: the current node in the traversal
1681 *
1682 * Traversal function for the "following" direction
1683 * The following axis contains all nodes in the same document as the context
1684 * node that are after the context node in document order, excluding any
1685 * descendants and excluding attribute nodes and namespace nodes; the nodes
1686 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001687 *
1688 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001689 */
1690xmlNodePtr
1691xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001692 if (cur == (xmlNodePtr) ctxt->context->doc)
1693 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001694 if (cur == NULL)
1695 return(ctxt->context->node->next);; /* !!!!!!!!! */
1696 if (cur->childs != NULL) return(cur->childs);
1697 if (cur->next != NULL) return(cur->next);
1698
1699 do {
1700 cur = cur->parent;
1701 if (cur == NULL) return(NULL);
1702 if (cur == ctxt->context->doc->root) return(NULL);
1703 if (cur->next != NULL) {
1704 cur = cur->next;
1705 return(cur);
1706 }
1707 } while (cur != NULL);
1708 return(cur);
1709}
1710
1711/**
1712 * xmlXPathNextPreceding:
1713 * @ctxt: the XPath Parser context
1714 * @cur: the current node in the traversal
1715 *
1716 * Traversal function for the "preceding" direction
1717 * the preceding axis contains all nodes in the same document as the context
1718 * node that are before the context node in document order, excluding any
1719 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1720 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001721 *
1722 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001723 */
1724xmlNodePtr
1725xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001726 if (cur == (xmlNodePtr) ctxt->context->doc)
1727 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001728 if (cur == NULL)
1729 return(ctxt->context->node->prev); /* !!!!!!!!! */
1730 if (cur->last != NULL) return(cur->last);
1731 if (cur->prev != NULL) return(cur->prev);
1732
1733 do {
1734 cur = cur->parent;
1735 if (cur == NULL) return(NULL);
1736 if (cur == ctxt->context->doc->root) return(NULL);
1737 if (cur->prev != NULL) {
1738 cur = cur->prev;
1739 return(cur);
1740 }
1741 } while (cur != NULL);
1742 return(cur);
1743}
1744
1745/**
1746 * xmlXPathNextNamespace:
1747 * @ctxt: the XPath Parser context
1748 * @cur: the current attribute in the traversal
1749 *
1750 * Traversal function for the "namespace" direction
1751 * the namespace axis contains the namespace nodes of the context node;
1752 * the order of nodes on this axis is implementation-defined; the axis will
1753 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001754 *
1755 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001756 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001757xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001758xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001759 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1760 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001761 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001762 ctxt->context->namespaces =
1763 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1764 if (ctxt->context->namespaces == NULL) return(NULL);
1765 ctxt->context->nsNr = 0;
1766 }
1767 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001768}
1769
1770/**
1771 * xmlXPathNextAttribute:
1772 * @ctxt: the XPath Parser context
1773 * @cur: the current attribute in the traversal
1774 *
1775 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001776 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001777 *
1778 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001779 */
1780xmlAttrPtr
1781xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001782 if (cur == NULL) {
1783 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1784 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001785 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001786 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001787 return(cur->next);
1788}
1789
1790/************************************************************************
1791 * *
1792 * NodeTest Functions *
1793 * *
1794 ************************************************************************/
1795
1796#define NODE_TEST_NONE 0
1797#define NODE_TEST_TYPE 1
1798#define NODE_TEST_PI 2
1799#define NODE_TEST_ALL 3
1800#define NODE_TEST_NS 4
1801#define NODE_TEST_NAME 5
1802
1803#define NODE_TYPE_COMMENT 50
1804#define NODE_TYPE_TEXT 51
1805#define NODE_TYPE_PI 52
1806#define NODE_TYPE_NODE 53
1807
1808#define IS_FUNCTION 200
1809
1810/**
1811 * xmlXPathNodeCollectAndTest:
1812 * @ctxt: the XPath Parser context
1813 * @cur: the current node to test
1814 *
1815 * This is the function implementing a step: based on the current list
1816 * of nodes, it builds up a new list, looking at all nodes under that
1817 * axis and selecting them.
1818 *
1819 * Returns the new NodeSet resulting from the search.
1820 */
1821xmlNodeSetPtr
1822xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001823 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001824#ifdef DEBUG_STEP
1825 int n = 0, t = 0;
1826#endif
1827 int i;
1828 xmlNodeSetPtr ret;
1829 xmlXPathTraversalFunction next = NULL;
1830 xmlNodePtr cur = NULL;
1831
1832 if (ctxt->context->nodelist == NULL) {
1833 if (ctxt->context->node == NULL) {
1834 fprintf(xmlXPathDebug,
1835 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1836 __FILE__, __LINE__);
1837 return(NULL);
1838 }
1839 STRANGE
1840 return(NULL);
1841 }
1842#ifdef DEBUG_STEP
1843 fprintf(xmlXPathDebug, "new step : ");
1844#endif
1845 switch (axis) {
1846 case AXIS_ANCESTOR:
1847#ifdef DEBUG_STEP
1848 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1849#endif
1850 next = xmlXPathNextAncestor; break;
1851 case AXIS_ANCESTOR_OR_SELF:
1852#ifdef DEBUG_STEP
1853 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1854#endif
1855 next = xmlXPathNextAncestorOrSelf; break;
1856 case AXIS_ATTRIBUTE:
1857#ifdef DEBUG_STEP
1858 fprintf(xmlXPathDebug, "axis 'attributes' ");
1859#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001860 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001861 break;
1862 case AXIS_CHILD:
1863#ifdef DEBUG_STEP
1864 fprintf(xmlXPathDebug, "axis 'child' ");
1865#endif
1866 next = xmlXPathNextChild; break;
1867 case AXIS_DESCENDANT:
1868#ifdef DEBUG_STEP
1869 fprintf(xmlXPathDebug, "axis 'descendant' ");
1870#endif
1871 next = xmlXPathNextDescendant; break;
1872 case AXIS_DESCENDANT_OR_SELF:
1873#ifdef DEBUG_STEP
1874 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1875#endif
1876 next = xmlXPathNextDescendantOrSelf; break;
1877 case AXIS_FOLLOWING:
1878#ifdef DEBUG_STEP
1879 fprintf(xmlXPathDebug, "axis 'following' ");
1880#endif
1881 next = xmlXPathNextFollowing; break;
1882 case AXIS_FOLLOWING_SIBLING:
1883#ifdef DEBUG_STEP
1884 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1885#endif
1886 next = xmlXPathNextFollowingSibling; break;
1887 case AXIS_NAMESPACE:
1888#ifdef DEBUG_STEP
1889 fprintf(xmlXPathDebug, "axis 'namespace' ");
1890#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001891 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001892 break;
1893 case AXIS_PARENT:
1894#ifdef DEBUG_STEP
1895 fprintf(xmlXPathDebug, "axis 'parent' ");
1896#endif
1897 next = xmlXPathNextParent; break;
1898 case AXIS_PRECEDING:
1899#ifdef DEBUG_STEP
1900 fprintf(xmlXPathDebug, "axis 'preceding' ");
1901#endif
1902 next = xmlXPathNextPreceding; break;
1903 case AXIS_PRECEDING_SIBLING:
1904#ifdef DEBUG_STEP
1905 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1906#endif
1907 next = xmlXPathNextPrecedingSibling; break;
1908 case AXIS_SELF:
1909#ifdef DEBUG_STEP
1910 fprintf(xmlXPathDebug, "axis 'self' ");
1911#endif
1912 next = xmlXPathNextSelf; break;
1913 }
1914 if (next == NULL) return(NULL);
1915 ret = xmlXPathNodeSetCreate(NULL);
1916#ifdef DEBUG_STEP
1917 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1918 ctxt->context->nodelist->nodeNr);
1919 switch (test) {
1920 case NODE_TEST_NONE:
1921 fprintf(xmlXPathDebug, " seaching for none !!!\n");
1922 break;
1923 case NODE_TEST_TYPE:
1924 fprintf(xmlXPathDebug, " seaching for type %d\n", type);
1925 break;
1926 case NODE_TEST_PI:
1927 fprintf(xmlXPathDebug, " seaching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001928 break;
1929 case NODE_TEST_ALL:
1930 fprintf(xmlXPathDebug, " seaching for *\n");
1931 break;
1932 case NODE_TEST_NS:
1933 fprintf(xmlXPathDebug, " seaching for namespace %s\n",
1934 prefix);
1935 break;
1936 case NODE_TEST_NAME:
1937 fprintf(xmlXPathDebug, " seaching for name %s\n", name);
1938 if (prefix != NULL)
1939 fprintf(xmlXPathDebug, " with namespace %s\n",
1940 prefix);
1941 break;
1942 }
1943 fprintf(xmlXPathDebug, "Testing : ");
1944#endif
1945 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1946 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1947
1948 cur = NULL;
1949 do {
1950 cur = next(ctxt, cur);
1951 if (cur == NULL) break;
1952#ifdef DEBUG_STEP
1953 t++;
1954 fprintf(xmlXPathDebug, " %s", cur->name);
1955#endif
1956 switch (test) {
1957 case NODE_TEST_NONE:
1958 STRANGE
1959 return(NULL);
1960 case NODE_TEST_TYPE:
1961 if (cur->type == type) {
1962#ifdef DEBUG_STEP
1963 n++;
1964#endif
1965 xmlXPathNodeSetAdd(ret, cur);
1966 }
1967 break;
1968 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001969 if (cur->type == XML_PI_NODE) {
1970 if ((name != NULL) &&
1971 (xmlStrcmp(name, cur->name)))
1972 break;
1973#ifdef DEBUG_STEP
1974 n++;
1975#endif
1976 xmlXPathNodeSetAdd(ret, cur);
1977 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001978 break;
1979 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001980 if ((cur->type == XML_ELEMENT_NODE) ||
1981 (cur->type == XML_ATTRIBUTE_NODE)) {
1982 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001983#ifdef DEBUG_STEP
1984 n++;
1985#endif
1986 xmlXPathNodeSetAdd(ret, cur);
1987 }
1988 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001989 case NODE_TEST_NS: {
1990 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001991 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001992 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001993 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001994 switch (cur->type) {
1995 case XML_ELEMENT_NODE:
1996 if (!xmlStrcmp(name, cur->name) &&
1997 (((prefix == NULL) ||
1998 ((cur->ns != NULL) &&
1999 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002000#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002001 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002002#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002003 xmlXPathNodeSetAdd(ret, cur);
2004 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002005 break;
2006 case XML_ATTRIBUTE_NODE: {
2007 xmlAttrPtr attr = (xmlAttrPtr) cur;
2008 if (!xmlStrcmp(name, attr->name)) {
2009#ifdef DEBUG_STEP
2010 n++;
2011#endif
2012 xmlXPathNodeSetAdd(ret, cur);
2013 }
2014 break;
2015 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002016 default:
2017 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002018 }
2019 break;
2020
2021 }
2022 } while (cur != NULL);
2023 }
2024#ifdef DEBUG_STEP
2025 fprintf(xmlXPathDebug,
2026 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2027#endif
2028 return(ret);
2029}
2030
2031
2032/************************************************************************
2033 * *
2034 * Implicit tree core function library *
2035 * *
2036 ************************************************************************/
2037
2038/**
2039 * xmlXPathRoot:
2040 * @ctxt: the XPath Parser context
2041 *
2042 * Initialize the context to the root of the document
2043 */
2044void
2045xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2046 if (ctxt->context->nodelist != NULL)
2047 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002048 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2049 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002050}
2051
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002052/************************************************************************
2053 * *
2054 * The explicit core function library *
2055 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2056 * *
2057 ************************************************************************/
2058
2059
2060/**
2061 * xmlXPathLastFunction:
2062 * @ctxt: the XPath Parser context
2063 *
2064 * Implement the last() XPath function
2065 * The last function returns the number of nodes in the context node list.
2066 */
2067void
2068xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2069 CHECK_ARITY(0);
2070 if ((ctxt->context->nodelist == NULL) ||
2071 (ctxt->context->node == NULL) ||
2072 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002073 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002074 } else {
2075 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002076 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002077 }
2078}
2079
2080/**
2081 * xmlXPathPositionFunction:
2082 * @ctxt: the XPath Parser context
2083 *
2084 * Implement the position() XPath function
2085 * The position function returns the position of the context node in the
2086 * context node list. The first position is 1, and so the last positionr
2087 * will be equal to last().
2088 */
2089void
2090xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2091 int i;
2092
2093 CHECK_ARITY(0);
2094 if ((ctxt->context->nodelist == NULL) ||
2095 (ctxt->context->node == NULL) ||
2096 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002097 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002098 }
2099 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2100 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002101 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002102 return;
2103 }
2104 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002105 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002106}
2107
2108/**
2109 * xmlXPathCountFunction:
2110 * @ctxt: the XPath Parser context
2111 *
2112 * Implement the count() XPath function
2113 */
2114void
2115xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2116 xmlXPathObjectPtr cur;
2117
2118 CHECK_ARITY(1);
2119 CHECK_TYPE(XPATH_NODESET);
2120 cur = valuePop(ctxt);
2121
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002122 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002123 xmlXPathFreeObject(cur);
2124}
2125
2126/**
2127 * xmlXPathIdFunction:
2128 * @ctxt: the XPath Parser context
2129 *
2130 * Implement the id() XPath function
2131 * The id function selects elements by their unique ID
2132 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2133 * then the result is the union of the result of applying id to the
2134 * string value of each of the nodes in the argument node-set. When the
2135 * argument to id is of any other type, the argument is converted to a
2136 * string as if by a call to the string function; the string is split
2137 * into a whitespace-separated list of tokens (whitespace is any sequence
2138 * of characters matching the production S); the result is a node-set
2139 * containing the elements in the same document as the context node that
2140 * have a unique ID equal to any of the tokens in the list.
2141 */
2142void
2143xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002144 const xmlChar *tokens;
2145 const xmlChar *cur;
2146 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002147 xmlAttrPtr attr;
2148 xmlNodePtr elem = NULL;
2149 xmlXPathObjectPtr ret, obj;
2150
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002151 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002152 obj = valuePop(ctxt);
2153 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2154 if (obj->type == XPATH_NODESET) {
2155 TODO /* ID function in case of NodeSet */
2156 }
2157 if (obj->type != XPATH_STRING) {
2158 valuePush(ctxt, obj);
2159 xmlXPathStringFunction(ctxt, 1);
2160 obj = valuePop(ctxt);
2161 if (obj->type != XPATH_STRING) {
2162 xmlXPathFreeObject(obj);
2163 return;
2164 }
2165 }
2166 tokens = obj->stringval;
2167
2168 ret = xmlXPathNewNodeSet(NULL);
2169 valuePush(ctxt, ret);
2170 if (tokens == NULL) {
2171 xmlXPathFreeObject(obj);
2172 return;
2173 }
2174
2175 cur = tokens;
2176
2177 while (IS_BLANK(*cur)) cur++;
2178 while (*cur != 0) {
2179 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2180 (*cur == '.') || (*cur == '-') ||
2181 (*cur == '_') || (*cur == ':') ||
2182 (IS_COMBINING(*cur)) ||
2183 (IS_EXTENDER(*cur)))
2184 cur++;
2185
2186 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2187
2188 ID = xmlStrndup(tokens, cur - tokens);
2189 attr = xmlGetID(ctxt->context->doc, ID);
2190 if (attr != NULL) {
2191 elem = attr->node;
2192 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2193 }
2194 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002195 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002196
2197 while (IS_BLANK(*cur)) cur++;
2198 tokens = cur;
2199 }
2200 xmlXPathFreeObject(obj);
2201 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002202}
2203
2204/**
2205 * xmlXPathLocalPartFunction:
2206 * @ctxt: the XPath Parser context
2207 *
2208 * Implement the local-part() XPath function
2209 * The local-part function returns a string containing the local part
2210 * of the name of the node in the argument node-set that is first in
2211 * document order. If the node-set is empty or the first node has no
2212 * name, an empty string is returned. If the argument is omitted it
2213 * defaults to the context node.
2214 */
2215void
2216xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2217 xmlXPathObjectPtr cur;
2218
2219 CHECK_ARITY(1);
2220 CHECK_TYPE(XPATH_NODESET);
2221 cur = valuePop(ctxt);
2222
2223 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002224 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002225 } else {
2226 int i = 0; /* Should be first in document order !!!!! */
2227 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2228 }
2229 xmlXPathFreeObject(cur);
2230}
2231
2232/**
2233 * xmlXPathNamespaceFunction:
2234 * @ctxt: the XPath Parser context
2235 *
2236 * Implement the namespace() XPath function
2237 * The namespace function returns a string containing the namespace URI
2238 * of the expanded name of the node in the argument node-set that is
2239 * first in document order. If the node-set is empty, the first node has
2240 * no name, or the expanded name has no namespace URI, an empty string
2241 * is returned. If the argument is omitted it defaults to the context node.
2242 */
2243void
2244xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2245 xmlXPathObjectPtr cur;
2246
Daniel Veillardb96e6431999-08-29 21:02:19 +00002247 if (nargs == 0) {
2248 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2249 nargs = 1;
2250 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002251 CHECK_ARITY(1);
2252 CHECK_TYPE(XPATH_NODESET);
2253 cur = valuePop(ctxt);
2254
2255 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002256 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002257 } else {
2258 int i = 0; /* Should be first in document order !!!!! */
2259
2260 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002261 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002262 else
2263 valuePush(ctxt, xmlXPathNewString(
2264 cur->nodesetval->nodeTab[i]->ns->href));
2265 }
2266 xmlXPathFreeObject(cur);
2267}
2268
2269/**
2270 * xmlXPathNameFunction:
2271 * @ctxt: the XPath Parser context
2272 *
2273 * Implement the name() XPath function
2274 * The name function returns a string containing a QName representing
2275 * the name of the node in the argument node-set that is first in documenti
2276 * order. The QName must represent the name with respect to the namespace
2277 * declarations in effect on the node whose name is being represented.
2278 * Typically, this will be the form in which the name occurred in the XML
2279 * source. This need not be the case if there are namespace declarations
2280 * in effect on the node that associate multiple prefixes with the same
2281 * namespace. However, an implementation may include information about
2282 * the original prefix in its representation of nodes; in this case, an
2283 * implementation can ensure that the returned string is always the same
2284 * as the QName used in the XML source. If the argument it omitted it
2285 * defaults to the context node.
2286 * Libxml keep the original prefix so the "real qualified name" used is
2287 * returned.
2288 */
2289void
2290xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2291 xmlXPathObjectPtr cur;
2292
2293 CHECK_ARITY(1);
2294 CHECK_TYPE(XPATH_NODESET);
2295 cur = valuePop(ctxt);
2296
2297 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002298 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002299 } else {
2300 int i = 0; /* Should be first in document order !!!!! */
2301
2302 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2303 valuePush(ctxt, xmlXPathNewString(
2304 cur->nodesetval->nodeTab[i]->name));
2305
2306 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002307 char name[2000];
2308 sprintf(name, "%s:%s",
2309 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2310 (char *) cur->nodesetval->nodeTab[i]->name);
2311 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002312 }
2313 }
2314 xmlXPathFreeObject(cur);
2315}
2316
2317/**
2318 * xmlXPathStringFunction:
2319 * @ctxt: the XPath Parser context
2320 *
2321 * Implement the string() XPath function
2322 * he string function converts an object to a string as follows:
2323 * - A node-set is converted to a string by returning the value of
2324 * the node in the node-set that is first in document order.
2325 * If the node-set is empty, an empty string is returned.
2326 * - A number is converted to a string as follows
2327 * + NaN is converted to the string NaN
2328 * + positive zero is converted to the string 0
2329 * + negative zero is converted to the string 0
2330 * + positive infinity is converted to the string Infinity
2331 * + negative infinity is converted to the string -Infinity
2332 * + if the number is an integer, the number is represented in
2333 * decimal form as a Number with no decimal point and no leading
2334 * zeros, preceded by a minus sign (-) if the number is negative
2335 * + otherwise, the number is represented in decimal form as a
2336 * Number including a decimal point with at least one digit
2337 * before the decimal point and at least one digit after the
2338 * decimal point, preceded by a minus sign (-) if the number
2339 * is negative; there must be no leading zeros before the decimal
2340 * point apart possibly from the one required digit immediatelyi
2341 * before the decimal point; beyond the one required digit
2342 * after the decimal point there must be as many, but only as
2343 * many, more digits as are needed to uniquely distinguish the
2344 * number from all other IEEE 754 numeric values.
2345 * - The boolean false value is converted to the string false.
2346 * The boolean true value is converted to the string true.
2347 */
2348void
2349xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2350 xmlXPathObjectPtr cur;
2351
2352 CHECK_ARITY(1);
2353 cur = valuePop(ctxt);
2354 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2355 switch (cur->type) {
2356 case XPATH_NODESET:
2357 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002358 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002359 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002360 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002361 int i = 0; /* Should be first in document order !!!!! */
2362 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2363 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002364 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002365 }
2366 xmlXPathFreeObject(cur);
2367 return;
2368 case XPATH_STRING:
2369 valuePush(ctxt, cur);
2370 return;
2371 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002372 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2373 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002374 xmlXPathFreeObject(cur);
2375 return;
2376 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002377 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002378
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002379 if (isnan(cur->floatval))
2380 sprintf(buf, "NaN");
2381 else if (isinf(cur->floatval) > 0)
2382 sprintf(buf, "+Infinity");
2383 else if (isinf(cur->floatval) < 0)
2384 sprintf(buf, "-Infinity");
2385 else
2386 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002387 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002388 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002389 return;
2390 }
2391 }
2392 STRANGE
2393}
2394
2395/**
2396 * xmlXPathStringLengthFunction:
2397 * @ctxt: the XPath Parser context
2398 *
2399 * Implement the string-length() XPath function
2400 * The string-length returns the number of characters in the string
2401 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2402 * the context node converted to a string, in other words the value
2403 * of the context node.
2404 */
2405void
2406xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2407 xmlXPathObjectPtr cur;
2408
2409 if (nargs == 0) {
2410 if (ctxt->context->node == NULL) {
2411 valuePush(ctxt, xmlXPathNewFloat(0));
2412 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002413 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002414
2415 content = xmlNodeGetContent(ctxt->context->node);
2416 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002417 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002418 }
2419 return;
2420 }
2421 CHECK_ARITY(1);
2422 CHECK_TYPE(XPATH_STRING);
2423 cur = valuePop(ctxt);
2424 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2425 xmlXPathFreeObject(cur);
2426}
2427
2428/**
2429 * xmlXPathConcatFunction:
2430 * @ctxt: the XPath Parser context
2431 *
2432 * Implement the concat() XPath function
2433 * The concat function returns the concatenation of its arguments.
2434 */
2435void
2436xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2437 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002438 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002439
2440 if (nargs < 2) {
2441 CHECK_ARITY(2);
2442 }
2443
2444 cur = valuePop(ctxt);
2445 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2446 xmlXPathFreeObject(cur);
2447 return;
2448 }
2449 nargs--;
2450
2451 while (nargs > 0) {
2452 new = valuePop(ctxt);
2453 if ((new == NULL) || (new->type != XPATH_STRING)) {
2454 xmlXPathFreeObject(new);
2455 xmlXPathFreeObject(cur);
2456 ERROR(XPATH_INVALID_TYPE);
2457 }
2458 tmp = xmlStrcat(new->stringval, cur->stringval);
2459 new->stringval = cur->stringval;
2460 cur->stringval = tmp;
2461
2462 xmlXPathFreeObject(new);
2463 nargs--;
2464 }
2465 valuePush(ctxt, cur);
2466}
2467
2468/**
2469 * xmlXPathContainsFunction:
2470 * @ctxt: the XPath Parser context
2471 *
2472 * Implement the contains() XPath function
2473 * The contains function returns true if the first argument string
2474 * contains the second argument string, and otherwise returns false.
2475 */
2476void
2477xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2478 xmlXPathObjectPtr hay, needle;
2479
2480 CHECK_ARITY(2);
2481 CHECK_TYPE(XPATH_STRING);
2482 needle = valuePop(ctxt);
2483 hay = valuePop(ctxt);
2484 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2485 xmlXPathFreeObject(hay);
2486 xmlXPathFreeObject(needle);
2487 ERROR(XPATH_INVALID_TYPE);
2488 }
2489 if (xmlStrstr(hay->stringval, needle->stringval))
2490 valuePush(ctxt, xmlXPathNewBoolean(1));
2491 else
2492 valuePush(ctxt, xmlXPathNewBoolean(0));
2493 xmlXPathFreeObject(hay);
2494 xmlXPathFreeObject(needle);
2495}
2496
2497/**
2498 * xmlXPathStartsWithFunction:
2499 * @ctxt: the XPath Parser context
2500 *
2501 * Implement the starts-with() XPath function
2502 * The starts-with function returns true if the first argument string
2503 * starts with the second argument string, and otherwise returns false.
2504 */
2505void
2506xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2507 xmlXPathObjectPtr hay, needle;
2508 int n;
2509
2510 CHECK_ARITY(2);
2511 CHECK_TYPE(XPATH_STRING);
2512 needle = valuePop(ctxt);
2513 hay = valuePop(ctxt);
2514 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2515 xmlXPathFreeObject(hay);
2516 xmlXPathFreeObject(needle);
2517 ERROR(XPATH_INVALID_TYPE);
2518 }
2519 n = xmlStrlen(needle->stringval);
2520 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2521 valuePush(ctxt, xmlXPathNewBoolean(0));
2522 else
2523 valuePush(ctxt, xmlXPathNewBoolean(1));
2524 xmlXPathFreeObject(hay);
2525 xmlXPathFreeObject(needle);
2526}
2527
2528/**
2529 * xmlXPathSubstringFunction:
2530 * @ctxt: the XPath Parser context
2531 *
2532 * Implement the substring() XPath function
2533 * The substring function returns the substring of the first argument
2534 * starting at the position specified in the second argument with
2535 * length specified in the third argument. For example,
2536 * substring("12345",2,3) returns "234". If the third argument is not
2537 * specified, it returns the substring starting at the position specified
2538 * in the second argument and continuing to the end of the string. For
2539 * example, substring("12345",2) returns "2345". More precisely, each
2540 * character in the string (see [3.6 Strings]) is considered to have a
2541 * numeric position: the position of the first character is 1, the position
2542 * of the second character is 2 and so on. The returned substring contains
2543 * those characters for which the position of the character is greater than
2544 * or equal to the second argument and, if the third argument is specified,
2545 * less than the sum of the second and third arguments; the comparisons
2546 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2547 * - substring("12345", 1.5, 2.6) returns "234"
2548 * - substring("12345", 0, 3) returns "12"
2549 * - substring("12345", 0 div 0, 3) returns ""
2550 * - substring("12345", 1, 0 div 0) returns ""
2551 * - substring("12345", -42, 1 div 0) returns "12345"
2552 * - substring("12345", -1 div 0, 1 div 0) returns ""
2553 */
2554void
2555xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2556 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002557 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002558 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002559 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002560
2561 /*
2562 * Conformance needs to be checked !!!!!
2563 */
2564 if (nargs < 2) {
2565 CHECK_ARITY(2);
2566 }
2567 if (nargs > 3) {
2568 CHECK_ARITY(3);
2569 }
2570 if (nargs == 3) {
2571 CHECK_TYPE(XPATH_NUMBER);
2572 len = valuePop(ctxt);
2573 le = len->floatval;
2574 xmlXPathFreeObject(len);
2575 } else {
2576 le = 2000000000;
2577 }
2578 CHECK_TYPE(XPATH_NUMBER);
2579 start = valuePop(ctxt);
2580 in = start->floatval;
2581 xmlXPathFreeObject(start);
2582 CHECK_TYPE(XPATH_STRING);
2583 str = valuePop(ctxt);
2584 le += in;
2585
2586 /* integer index of the first char */
2587 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002588 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002589
2590 /* integer index of the last char */
2591 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002592 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002593
2594 /* back to a zero based len */
2595 i--;
2596 l--;
2597
2598 /* check against the string len */
2599 if (l > 1024) {
2600 l = xmlStrlen(str->stringval);
2601 }
2602 if (i < 0) {
2603 i = 0;
2604 }
2605
2606 /* number of chars to copy */
2607 l -= i;
2608
2609 ret = xmlStrsub(str->stringval, i, l);
2610 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002611 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002612 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002613 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002614 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002615 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002616 xmlXPathFreeObject(str);
2617}
2618
2619/**
2620 * xmlXPathSubstringBeforeFunction:
2621 * @ctxt: the XPath Parser context
2622 *
2623 * Implement the substring-before() XPath function
2624 * The substring-before function returns the substring of the first
2625 * argument string that precedes the first occurrence of the second
2626 * argument string in the first argument string, or the empty string
2627 * if the first argument string does not contain the second argument
2628 * string. For example, substring-before("1999/04/01","/") returns 1999.
2629 */
2630void
2631xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2632 CHECK_ARITY(2);
2633 TODO /* substring before */
2634}
2635
2636/**
2637 * xmlXPathSubstringAfterFunction:
2638 * @ctxt: the XPath Parser context
2639 *
2640 * Implement the substring-after() XPath function
2641 * The substring-after function returns the substring of the first
2642 * argument string that follows the first occurrence of the second
2643 * argument string in the first argument string, or the empty stringi
2644 * if the first argument string does not contain the second argument
2645 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2646 * and substring-after("1999/04/01","19") returns 99/04/01.
2647 */
2648void
2649xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2650 CHECK_ARITY(2);
2651 TODO /* substring after */
2652}
2653
2654/**
2655 * xmlXPathNormalizeFunction:
2656 * @ctxt: the XPath Parser context
2657 *
2658 * Implement the normalize() XPath function
2659 * The normalize function returns the argument string with white
2660 * space normalized by stripping leading and trailing whitespace
2661 * and replacing sequences of whitespace characters by a single
2662 * space. Whitespace characters are the same allowed by the S production
2663 * in XML. If the argument is omitted, it defaults to the context
2664 * node converted to a string, in other words the value of the context node.
2665 */
2666void
2667xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2668 CHECK_ARITY(1);
2669 TODO /* normalize isn't as boring as translate, but pretty much */
2670}
2671
2672/**
2673 * xmlXPathTranslateFunction:
2674 * @ctxt: the XPath Parser context
2675 *
2676 * Implement the translate() XPath function
2677 * The translate function returns the first argument string with
2678 * occurrences of characters in the second argument string replaced
2679 * by the character at the corresponding position in the third argument
2680 * string. For example, translate("bar","abc","ABC") returns the string
2681 * BAr. If there is a character in the second argument string with no
2682 * character at a corresponding position in the third argument string
2683 * (because the second argument string is longer than the third argument
2684 * string), then occurrences of that character in the first argument
2685 * string are removed. For example, translate("--aaa--","abc-","ABC")
2686 * returns "AAA". If a character occurs more than once in second
2687 * argument string, then the first occurrence determines the replacement
2688 * character. If the third argument string is longer than the second
2689 * argument string, then excess characters are ignored.
2690 */
2691void
2692xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2693 CHECK_ARITY(3);
2694 TODO /* translate is boring, waiting for UTF-8 representation too */
2695}
2696
2697/**
2698 * xmlXPathBooleanFunction:
2699 * @ctxt: the XPath Parser context
2700 *
2701 * Implement the boolean() XPath function
2702 * he boolean function converts its argument to a boolean as follows:
2703 * - a number is true if and only if it is neither positive or
2704 * negative zero nor NaN
2705 * - a node-set is true if and only if it is non-empty
2706 * - a string is true if and only if its length is non-zero
2707 */
2708void
2709xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2710 xmlXPathObjectPtr cur;
2711 int res = 0;
2712
2713 CHECK_ARITY(1);
2714 cur = valuePop(ctxt);
2715 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2716 switch (cur->type) {
2717 case XPATH_NODESET:
2718 if ((cur->nodesetval == NULL) ||
2719 (cur->nodesetval->nodeNr == 0)) res = 0;
2720 else
2721 res = 1;
2722 break;
2723 case XPATH_STRING:
2724 if ((cur->stringval == NULL) ||
2725 (cur->stringval[0] == 0)) res = 0;
2726 else
2727 res = 1;
2728 break;
2729 case XPATH_BOOLEAN:
2730 valuePush(ctxt, cur);
2731 return;
2732 case XPATH_NUMBER:
2733 if (cur->floatval) res = 1;
2734 break;
2735 default:
2736 STRANGE
2737 }
2738 xmlXPathFreeObject(cur);
2739 valuePush(ctxt, xmlXPathNewBoolean(res));
2740}
2741
2742/**
2743 * xmlXPathNotFunction:
2744 * @ctxt: the XPath Parser context
2745 *
2746 * Implement the not() XPath function
2747 * The not function returns true if its argument is false,
2748 * and false otherwise.
2749 */
2750void
2751xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2752 CHECK_ARITY(1);
2753 CHECK_TYPE(XPATH_BOOLEAN);
2754 ctxt->value->boolval = ! ctxt->value->boolval;
2755}
2756
2757/**
2758 * xmlXPathTrueFunction:
2759 * @ctxt: the XPath Parser context
2760 *
2761 * Implement the true() XPath function
2762 */
2763void
2764xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2765 CHECK_ARITY(0);
2766 valuePush(ctxt, xmlXPathNewBoolean(1));
2767}
2768
2769/**
2770 * xmlXPathFalseFunction:
2771 * @ctxt: the XPath Parser context
2772 *
2773 * Implement the false() XPath function
2774 */
2775void
2776xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2777 CHECK_ARITY(0);
2778 valuePush(ctxt, xmlXPathNewBoolean(0));
2779}
2780
2781/**
2782 * xmlXPathLangFunction:
2783 * @ctxt: the XPath Parser context
2784 *
2785 * Implement the lang() XPath function
2786 * The lang function returns true or false depending on whether the
2787 * language of the context node as specified by xml:lang attributes
2788 * is the same as or is a sublanguage of the language specified by
2789 * the argument string. The language of the context node is determined
2790 * by the value of the xml:lang attribute on the context node, or, if
2791 * the context node has no xml:lang attribute, by the value of the
2792 * xml:lang attribute on the nearest ancestor of the context node that
2793 * has an xml:lang attribute. If there is no such attribute, then lang
2794 * returns false. If there is such an attribute, then lang returns
2795 * true if the attribute value is equal to the argument ignoring case,
2796 * or if there is some suffix starting with - such that the attribute
2797 * value is equal to the argument ignoring that suffix of the attribute
2798 * value and ignoring case.
2799 */
2800void
2801xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002802 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002803 const xmlChar *theLang;
2804 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002805 int ret = 0;
2806 int i;
2807
2808 CHECK_ARITY(1);
2809 CHECK_TYPE(XPATH_STRING);
2810 val = valuePop(ctxt);
2811 lang = val->stringval;
2812 theLang = xmlNodeGetLang(ctxt->context->node);
2813 if ((theLang != NULL) && (lang != NULL)) {
2814 for (i = 0;lang[i] != 0;i++)
2815 if (toupper(lang[i]) != toupper(theLang[i]))
2816 goto not_equal;
2817 ret = 1;
2818 }
2819not_equal:
2820 xmlXPathFreeObject(val);
2821 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002822}
2823
2824/**
2825 * xmlXPathNumberFunction:
2826 * @ctxt: the XPath Parser context
2827 *
2828 * Implement the number() XPath function
2829 */
2830void
2831xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2832 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002833 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002834
2835 CHECK_ARITY(1);
2836 cur = valuePop(ctxt);
2837 switch (cur->type) {
2838 case XPATH_NODESET:
2839 valuePush(ctxt, cur);
2840 xmlXPathStringFunction(ctxt, 1);
2841 cur = valuePop(ctxt);
2842 case XPATH_STRING:
2843 res = xmlXPathStringEvalNumber(cur->stringval);
2844 valuePush(ctxt, xmlXPathNewFloat(res));
2845 xmlXPathFreeObject(cur);
2846 return;
2847 case XPATH_BOOLEAN:
2848 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2849 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2850 xmlXPathFreeObject(cur);
2851 return;
2852 case XPATH_NUMBER:
2853 valuePush(ctxt, cur);
2854 return;
2855 }
2856 STRANGE
2857}
2858
2859/**
2860 * xmlXPathSumFunction:
2861 * @ctxt: the XPath Parser context
2862 *
2863 * Implement the sum() XPath function
2864 * The sum function returns the sum of the values of the nodes in
2865 * the argument node-set.
2866 */
2867void
2868xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2869 CHECK_ARITY(1);
2870 TODO /* BUG Sum : don't understand the definition */
2871}
2872
2873/**
2874 * xmlXPathFloorFunction:
2875 * @ctxt: the XPath Parser context
2876 *
2877 * Implement the floor() XPath function
2878 * The floor function returns the largest (closest to positive infinity)
2879 * number that is not greater than the argument and that is an integer.
2880 */
2881void
2882xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2883 CHECK_ARITY(1);
2884 CHECK_TYPE(XPATH_NUMBER);
2885 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002886 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002887}
2888
2889/**
2890 * xmlXPathCeilingFunction:
2891 * @ctxt: the XPath Parser context
2892 *
2893 * Implement the ceiling() XPath function
2894 * The ceiling function returns the smallest (closest to negative infinity)
2895 * number that is not less than the argument and that is an integer.
2896 */
2897void
2898xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002899 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002900
2901 CHECK_ARITY(1);
2902 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002903 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002904 if (f != ctxt->value->floatval)
2905 ctxt->value->floatval = f + 1;
2906}
2907
2908/**
2909 * xmlXPathRoundFunction:
2910 * @ctxt: the XPath Parser context
2911 *
2912 * Implement the round() XPath function
2913 * The round function returns the number that is closest to the
2914 * argument and that is an integer. If there are two such numbers,
2915 * then the one that is even is returned.
2916 */
2917void
2918xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002919 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002920
2921 CHECK_ARITY(1);
2922 CHECK_TYPE(XPATH_NUMBER);
2923 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002924 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002925 if (ctxt->value->floatval < f + 0.5)
2926 ctxt->value->floatval = f;
2927 else if (ctxt->value->floatval == f + 0.5)
2928 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2929 else
2930 ctxt->value->floatval = f + 1;
2931}
2932
2933/************************************************************************
2934 * *
2935 * The Parser *
2936 * *
2937 ************************************************************************/
2938
2939/*
2940 * a couple of forward declarations since we use a recursive call based
2941 * implementation.
2942 */
2943void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2944void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2945void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2946void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2947
2948/**
2949 * xmlXPathParseNCName:
2950 * @ctxt: the XPath Parser context
2951 *
2952 * parse an XML namespace non qualified name.
2953 *
2954 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2955 *
2956 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2957 * CombiningChar | Extender
2958 *
2959 * Returns the namespace name or NULL
2960 */
2961
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002962xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002963xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002964 const xmlChar *q;
2965 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002966
2967 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2968 q = NEXT;
2969
2970 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2971 (CUR == '.') || (CUR == '-') ||
2972 (CUR == '_') ||
2973 (IS_COMBINING(CUR)) ||
2974 (IS_EXTENDER(CUR)))
2975 NEXT;
2976
2977 ret = xmlStrndup(q, CUR_PTR - q);
2978
2979 return(ret);
2980}
2981
2982/**
2983 * xmlXPathParseQName:
2984 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002985 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002986 *
2987 * parse an XML qualified name
2988 *
2989 * [NS 5] QName ::= (Prefix ':')? LocalPart
2990 *
2991 * [NS 6] Prefix ::= NCName
2992 *
2993 * [NS 7] LocalPart ::= NCName
2994 *
2995 * Returns the function returns the local part, and prefix is updated
2996 * to get the Prefix if any.
2997 */
2998
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002999xmlChar *
3000xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3001 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003002
3003 *prefix = NULL;
3004 ret = xmlXPathParseNCName(ctxt);
3005 if (CUR == ':') {
3006 *prefix = ret;
3007 NEXT;
3008 ret = xmlXPathParseNCName(ctxt);
3009 }
3010 return(ret);
3011}
3012
3013/**
3014 * xmlXPathStringEvalNumber:
3015 * @str: A string to scan
3016 *
3017 * [30] Number ::= Digits ('.' Digits)?
3018 * | '.' Digits
3019 * [31] Digits ::= [0-9]+
3020 *
3021 * Parse and evaluate a Number in the string
3022 *
3023 * BUG: "1.' is not valid ... James promised correction
3024 * as Digits ('.' Digits?)?
3025 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003026 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003027 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003028double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003029xmlXPathStringEvalNumber(const xmlChar *str) {
3030 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003031 double ret = 0.0;
3032 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003033 int ok = 0;
3034
3035 while (*cur == ' ') cur++;
3036 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003037 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003038 }
3039 while ((*cur >= '0') && (*cur <= '9')) {
3040 ret = ret * 10 + (*cur - '0');
3041 ok = 1;
3042 cur++;
3043 }
3044 if (*cur == '.') {
3045 cur++;
3046 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003047 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003048 }
3049 while ((*cur >= '0') && (*cur <= '9')) {
3050 mult /= 10;
3051 ret = ret + (*cur - '0') * mult;
3052 cur++;
3053 }
3054 }
3055 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003056 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003057 return(ret);
3058}
3059
3060/**
3061 * xmlXPathEvalNumber:
3062 * @ctxt: the XPath Parser context
3063 *
3064 * [30] Number ::= Digits ('.' Digits)?
3065 * | '.' Digits
3066 * [31] Digits ::= [0-9]+
3067 *
3068 * Parse and evaluate a Number, then push it on the stack
3069 *
3070 * BUG: "1.' is not valid ... James promised correction
3071 * as Digits ('.' Digits?)?
3072 */
3073void
3074xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003075 double ret = 0.0;
3076 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003077 int ok = 0;
3078
3079 CHECK_ERROR;
3080 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3081 ERROR(XPATH_NUMBER_ERROR);
3082 }
3083 while ((CUR >= '0') && (CUR <= '9')) {
3084 ret = ret * 10 + (CUR - '0');
3085 ok = 1;
3086 NEXT;
3087 }
3088 if (CUR == '.') {
3089 NEXT;
3090 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3091 ERROR(XPATH_NUMBER_ERROR);
3092 }
3093 while ((CUR >= '0') && (CUR <= '9')) {
3094 mult /= 10;
3095 ret = ret + (CUR - '0') * mult;
3096 NEXT;
3097 }
3098 }
3099 valuePush(ctxt, xmlXPathNewFloat(ret));
3100}
3101
3102/**
3103 * xmlXPathEvalLiteral:
3104 * @ctxt: the XPath Parser context
3105 *
3106 * Parse a Literal and push it on the stack.
3107 *
3108 * [29] Literal ::= '"' [^"]* '"'
3109 * | "'" [^']* "'"
3110 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003111 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003112 */
3113void
3114xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003115 const xmlChar *q;
3116 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003117
3118 if (CUR == '"') {
3119 NEXT;
3120 q = CUR_PTR;
3121 while ((IS_CHAR(CUR)) && (CUR != '"'))
3122 NEXT;
3123 if (!IS_CHAR(CUR)) {
3124 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3125 } else {
3126 ret = xmlStrndup(q, CUR_PTR - q);
3127 NEXT;
3128 }
3129 } else if (CUR == '\'') {
3130 NEXT;
3131 q = CUR_PTR;
3132 while ((IS_CHAR(CUR)) && (CUR != '\''))
3133 NEXT;
3134 if (!IS_CHAR(CUR)) {
3135 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3136 } else {
3137 ret = xmlStrndup(q, CUR_PTR - q);
3138 NEXT;
3139 }
3140 } else {
3141 ERROR(XPATH_START_LITERAL_ERROR);
3142 }
3143 if (ret == NULL) return;
3144 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003145 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003146}
3147
3148/**
3149 * xmlXPathEvalVariableReference:
3150 * @ctxt: the XPath Parser context
3151 *
3152 * Parse a VariableReference, evaluate it and push it on the stack.
3153 *
3154 * The variable bindings consist of a mapping from variable names
3155 * to variable values. The value of a variable is an object, which
3156 * of any of the types that are possible for the value of an expression,
3157 * and may also be of additional types not specified here.
3158 *
3159 * Early evaluation is possible since:
3160 * The variable bindings [...] used to evaluate a subexpression are
3161 * always the same as those used to evaluate the containing expression.
3162 *
3163 * [36] VariableReference ::= '$' QName
3164 */
3165void
3166xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003167 xmlChar *name;
3168 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003169 xmlXPathObjectPtr value;
3170
3171 if (CUR != '$') {
3172 ERROR(XPATH_VARIABLE_REF_ERROR);
3173 }
3174 name = xmlXPathParseQName(ctxt, &prefix);
3175 if (name == NULL) {
3176 ERROR(XPATH_VARIABLE_REF_ERROR);
3177 }
3178 value = xmlXPathVariablelookup(ctxt, prefix, name);
3179 if (value == NULL) {
3180 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3181 }
3182 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003183 if (prefix != NULL) xmlFree(prefix);
3184 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003185}
3186
3187
3188/**
3189 * xmlXPathFunctionLookup:
3190 * @ctxt: the XPath Parser context
3191 * @name: a name string
3192 *
3193 * Search for a function of the given name
3194 *
3195 * [35] FunctionName ::= QName - NodeType
3196 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003197 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003198 *
3199 * Returns the xmlXPathFunction if found, or NULL otherwise
3200 */
3201xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003202xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003203 switch (name[0]) {
3204 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003205 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003206 return(xmlXPathBooleanFunction);
3207 break;
3208 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003209 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003210 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003211 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003212 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003213 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003214 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003215 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003216 return(xmlXPathContainsFunction);
3217 break;
3218 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003219 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003220 return(xmlXPathIdFunction);
3221 break;
3222 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003223 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003224 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003225 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003226 return(xmlXPathFloorFunction);
3227 break;
3228 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003229 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003230 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003231 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003232 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003233 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003234 return(xmlXPathLocalPartFunction);
3235 break;
3236 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003237 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003238 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003239 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003240 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003241 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003242 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003243 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3244 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003245 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003246 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003247 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003248 return(xmlXPathNumberFunction);
3249 break;
3250 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003251 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003252 return(xmlXPathPositionFunction);
3253 break;
3254 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003255 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003256 return(xmlXPathRoundFunction);
3257 break;
3258 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003259 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003260 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003261 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003262 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003263 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003264 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003265 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003266 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003267 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003268 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003269 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003270 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003271 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003272 return(xmlXPathSumFunction);
3273 break;
3274 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003275 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003276 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003277 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003278 return(xmlXPathTranslateFunction);
3279 break;
3280 }
3281 return(NULL);
3282}
3283
3284/**
3285 * xmlXPathEvalLocationPathName:
3286 * @ctxt: the XPath Parser context
3287 * @name: a name string
3288 *
3289 * Various names in the beginning of a LocationPath expression
3290 * indicate whether that's an Axis, a node type,
3291 *
3292 * [6] AxisName ::= 'ancestor'
3293 * | 'ancestor-or-self'
3294 * | 'attribute'
3295 * | 'child'
3296 * | 'descendant'
3297 * | 'descendant-or-self'
3298 * | 'following'
3299 * | 'following-sibling'
3300 * | 'namespace'
3301 * | 'parent'
3302 * | 'preceding'
3303 * | 'preceding-sibling'
3304 * | 'self'
3305 * [38] NodeType ::= 'comment'
3306 * | 'text'
3307 * | 'processing-instruction'
3308 * | 'node'
3309 */
3310int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003311xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003312 switch (name[0]) {
3313 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003314 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3315 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3316 return(AXIS_ANCESTOR_OR_SELF);
3317 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003318 break;
3319 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003320 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3321 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003322 break;
3323 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003324 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3325 return(AXIS_DESCENDANT);
3326 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3327 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003328 break;
3329 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003330 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3331 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3332 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003333 break;
3334 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003335 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3336 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003337 break;
3338 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003339 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3340 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3341 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3342 return(AXIS_PRECEDING_SIBLING);
3343 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3344 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003345 break;
3346 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003347 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003348 break;
3349 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003350 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003351 break;
3352 }
3353 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3354 return(0);
3355}
3356
3357/**
3358 * xmlXPathEvalFunctionCall:
3359 * @ctxt: the XPath Parser context
3360 *
3361 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3362 * [17] Argument ::= Expr
3363 *
3364 * Parse and evaluate a function call, the evaluation of all arguments are
3365 * pushed on the stack
3366 */
3367void
3368xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003369 xmlChar *name;
3370 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003371 xmlXPathFunction func;
3372 int nbargs = 0;
3373
3374 name = xmlXPathParseQName(ctxt, &prefix);
3375 if (name == NULL) {
3376 ERROR(XPATH_EXPR_ERROR);
3377 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003378 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003379 func = xmlXPathIsFunction(ctxt, name);
3380 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003381 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003382 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3383 }
3384#ifdef DEBUG_EXPR
3385 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3386#endif
3387
3388 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003389 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003390 ERROR(XPATH_EXPR_ERROR);
3391 }
3392 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003393 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003394
3395 while (CUR != ')') {
3396 xmlXPathEvalExpr(ctxt);
3397 nbargs++;
3398 if (CUR == ')') break;
3399 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003400 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003401 ERROR(XPATH_EXPR_ERROR);
3402 }
3403 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003404 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003405 }
3406 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003407 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003408 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003409 func(ctxt, nbargs);
3410}
3411
3412/**
3413 * xmlXPathEvalPrimaryExpr:
3414 * @ctxt: the XPath Parser context
3415 *
3416 * [15] PrimaryExpr ::= VariableReference
3417 * | '(' Expr ')'
3418 * | Literal
3419 * | Number
3420 * | FunctionCall
3421 *
3422 * Parse and evaluate a primary expression, then push the result on the stack
3423 */
3424void
3425xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003426 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003427 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3428 else if (CUR == '(') {
3429 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003430 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003431 xmlXPathEvalExpr(ctxt);
3432 if (CUR != ')') {
3433 ERROR(XPATH_EXPR_ERROR);
3434 }
3435 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003436 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003437 } else if (IS_DIGIT(CUR)) {
3438 xmlXPathEvalNumber(ctxt);
3439 } else if ((CUR == '\'') || (CUR == '"')) {
3440 xmlXPathEvalLiteral(ctxt);
3441 } else {
3442 xmlXPathEvalFunctionCall(ctxt);
3443 }
3444}
3445
3446/**
3447 * xmlXPathEvalFilterExpr:
3448 * @ctxt: the XPath Parser context
3449 *
3450 * [20] FilterExpr ::= PrimaryExpr
3451 * | FilterExpr Predicate
3452 *
3453 * Parse and evaluate a filter expression, then push the result on the stack
3454 * Square brackets are used to filter expressions in the same way that
3455 * they are used in location paths. It is an error if the expression to
3456 * be filtered does not evaluate to a node-set. The context node list
3457 * used for evaluating the expression in square brackets is the node-set
3458 * to be filtered listed in document order.
3459 */
3460
3461void
3462xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3463 /****
3464 xmlNodeSetPtr oldset = NULL;
3465 xmlXPathObjectPtr arg;
3466 ****/
3467
3468 xmlXPathEvalPrimaryExpr(ctxt);
3469 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003470 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003471
3472 if (CUR != '[') return;
3473
3474 CHECK_TYPE(XPATH_NODESET);
3475
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003476 while (CUR == '[') {
3477 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003478 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003479 }
3480
3481
3482}
3483
3484/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003485 * xmlXPathScanName:
3486 * @ctxt: the XPath Parser context
3487 *
3488 * Trickery: parse an XML name but without consuming the input flow
3489 * Needed for rollback cases.
3490 *
3491 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3492 * CombiningChar | Extender
3493 *
3494 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3495 *
3496 * [6] Names ::= Name (S Name)*
3497 *
3498 * Returns the Name parsed or NULL
3499 */
3500
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003501xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003502xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003503 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003504 int len = 0;
3505
Daniel Veillard00fdf371999-10-08 09:40:39 +00003506 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003507 if (!IS_LETTER(CUR) && (CUR != '_') &&
3508 (CUR != ':')) {
3509 return(NULL);
3510 }
3511
3512 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3513 (NXT(len) == '.') || (NXT(len) == '-') ||
3514 (NXT(len) == '_') || (NXT(len) == ':') ||
3515 (IS_COMBINING(NXT(len))) ||
3516 (IS_EXTENDER(NXT(len)))) {
3517 buf[len] = NXT(len);
3518 len++;
3519 if (len >= XML_MAX_NAMELEN) {
3520 fprintf(stderr,
3521 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3522 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3523 (NXT(len) == '.') || (NXT(len) == '-') ||
3524 (NXT(len) == '_') || (NXT(len) == ':') ||
3525 (IS_COMBINING(NXT(len))) ||
3526 (IS_EXTENDER(NXT(len))))
3527 len++;
3528 break;
3529 }
3530 }
3531 return(xmlStrndup(buf, len));
3532}
3533
3534/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003535 * xmlXPathEvalPathExpr:
3536 * @ctxt: the XPath Parser context
3537 *
3538 * [19] PathExpr ::= LocationPath
3539 * | FilterExpr
3540 * | FilterExpr '/' RelativeLocationPath
3541 * | FilterExpr '//' RelativeLocationPath
3542 *
3543 * Parse and evaluate a path expression, then push the result on the stack
3544 * The / operator and // operators combine an arbitrary expression
3545 * and a relative location path. It is an error if the expression
3546 * does not evaluate to a node-set.
3547 * The / operator does composition in the same way as when / is
3548 * used in a location path. As in location paths, // is short for
3549 * /descendant-or-self::node()/.
3550 */
3551
3552void
3553xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3554 xmlNodeSetPtr newset = NULL;
3555
Daniel Veillard00fdf371999-10-08 09:40:39 +00003556 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003557 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3558 (CUR == '\'') || (CUR == '"')) {
3559 xmlXPathEvalFilterExpr(ctxt);
3560 CHECK_ERROR;
3561 if ((CUR == '/') && (NXT(1) == '/')) {
3562 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003563 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003564 if (ctxt->context->nodelist == NULL) {
3565 STRANGE
3566 xmlXPathRoot(ctxt);
3567 }
3568 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3569 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3570 if (ctxt->context->nodelist != NULL)
3571 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3572 ctxt->context->nodelist = newset;
3573 ctxt->context->node = NULL;
3574 xmlXPathEvalRelativeLocationPath(ctxt);
3575 } else if (CUR == '/') {
3576 xmlXPathEvalRelativeLocationPath(ctxt);
3577 }
3578 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003579 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003580 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003581
3582 name = xmlXPathScanName(ctxt);
3583 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3584 xmlXPathEvalLocationPath(ctxt);
3585 else
3586 xmlXPathEvalFilterExpr(ctxt);
3587 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003588 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003589 }
3590}
3591
3592/**
3593 * xmlXPathEvalUnionExpr:
3594 * @ctxt: the XPath Parser context
3595 *
3596 * [18] UnionExpr ::= PathExpr
3597 * | UnionExpr '|' PathExpr
3598 *
3599 * Parse and evaluate an union expression, then push the result on the stack
3600 */
3601
3602void
3603xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3604 xmlXPathEvalPathExpr(ctxt);
3605 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003606 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003607 if (CUR == '|') {
3608 xmlNodeSetPtr old = ctxt->context->nodelist;
3609
Daniel Veillard00fdf371999-10-08 09:40:39 +00003610 NEXT;
3611 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003612 xmlXPathEvalPathExpr(ctxt);
3613
3614 if (ctxt->context->nodelist == NULL)
3615 ctxt->context->nodelist = old;
3616 else {
3617 ctxt->context->nodelist =
3618 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3619 xmlXPathFreeNodeSet(old);
3620 }
3621 }
3622}
3623
3624/**
3625 * xmlXPathEvalUnaryExpr:
3626 * @ctxt: the XPath Parser context
3627 *
3628 * [27] UnaryExpr ::= UnionExpr
3629 * | '-' UnaryExpr
3630 *
3631 * Parse and evaluate an unary expression, then push the result on the stack
3632 */
3633
3634void
3635xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3636 int minus = 0;
3637
Daniel Veillard00fdf371999-10-08 09:40:39 +00003638 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003639 if (CUR == '-') {
3640 minus = 1;
3641 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003642 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003643 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003644 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003645 CHECK_ERROR;
3646 if (minus) {
3647 xmlXPathValueFlipSign(ctxt);
3648 }
3649}
3650
3651/**
3652 * xmlXPathEvalMultiplicativeExpr:
3653 * @ctxt: the XPath Parser context
3654 *
3655 * [26] MultiplicativeExpr ::= UnaryExpr
3656 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3657 * | MultiplicativeExpr 'div' UnaryExpr
3658 * | MultiplicativeExpr 'mod' UnaryExpr
3659 * [34] MultiplyOperator ::= '*'
3660 *
3661 * Parse and evaluate an Additive expression, then push the result on the stack
3662 */
3663
3664void
3665xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3666 xmlXPathEvalUnaryExpr(ctxt);
3667 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003668 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003669 while ((CUR == '*') ||
3670 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3671 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3672 int op = -1;
3673
3674 if (CUR == '*') {
3675 op = 0;
3676 NEXT;
3677 } else if (CUR == 'd') {
3678 op = 1;
3679 SKIP(3);
3680 } else if (CUR == 'm') {
3681 op = 2;
3682 SKIP(3);
3683 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003684 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003685 xmlXPathEvalUnaryExpr(ctxt);
3686 CHECK_ERROR;
3687 switch (op) {
3688 case 0:
3689 xmlXPathMultValues(ctxt);
3690 break;
3691 case 1:
3692 xmlXPathDivValues(ctxt);
3693 break;
3694 case 2:
3695 xmlXPathModValues(ctxt);
3696 break;
3697 }
3698 }
3699}
3700
3701/**
3702 * xmlXPathEvalAdditiveExpr:
3703 * @ctxt: the XPath Parser context
3704 *
3705 * [25] AdditiveExpr ::= MultiplicativeExpr
3706 * | AdditiveExpr '+' MultiplicativeExpr
3707 * | AdditiveExpr '-' MultiplicativeExpr
3708 *
3709 * Parse and evaluate an Additive expression, then push the result on the stack
3710 */
3711
3712void
3713xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3714 xmlXPathEvalMultiplicativeExpr(ctxt);
3715 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003716 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003717 while ((CUR == '+') || (CUR == '-')) {
3718 int plus;
3719
3720 if (CUR == '+') plus = 1;
3721 else plus = 0;
3722 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003723 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003724 xmlXPathEvalMultiplicativeExpr(ctxt);
3725 CHECK_ERROR;
3726 if (plus) xmlXPathAddValues(ctxt);
3727 else xmlXPathSubValues(ctxt);
3728 }
3729}
3730
3731/**
3732 * xmlXPathEvalRelationalExpr:
3733 * @ctxt: the XPath Parser context
3734 *
3735 * [24] RelationalExpr ::= AdditiveExpr
3736 * | RelationalExpr '<' AdditiveExpr
3737 * | RelationalExpr '>' AdditiveExpr
3738 * | RelationalExpr '<=' AdditiveExpr
3739 * | RelationalExpr '>=' AdditiveExpr
3740 *
3741 * A <= B > C is allowed ? Answer from James, yes with
3742 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3743 * which is basically what got implemented.
3744 *
3745 * Parse and evaluate a Relational expression, then push the result
3746 * on the stack
3747 */
3748
3749void
3750xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3751 xmlXPathEvalAdditiveExpr(ctxt);
3752 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003753 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003754 while ((CUR == '<') ||
3755 (CUR == '>') ||
3756 ((CUR == '<') && (NXT(1) == '=')) ||
3757 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003758 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003759
3760 if (CUR == '<') inf = 1;
3761 else inf = 0;
3762 if (NXT(1) == '=') strict = 0;
3763 else strict = 1;
3764 NEXT;
3765 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003766 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003767 xmlXPathEvalAdditiveExpr(ctxt);
3768 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003769 ret = xmlXPathCompareValues(ctxt, inf, strict);
3770 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003771 }
3772}
3773
3774/**
3775 * xmlXPathEvalEqualityExpr:
3776 * @ctxt: the XPath Parser context
3777 *
3778 * [23] EqualityExpr ::= RelationalExpr
3779 * | EqualityExpr '=' RelationalExpr
3780 * | EqualityExpr '!=' RelationalExpr
3781 *
3782 * A != B != C is allowed ? Answer from James, yes with
3783 * (RelationalExpr = RelationalExpr) = RelationalExpr
3784 * (RelationalExpr != RelationalExpr) != RelationalExpr
3785 * which is basically what got implemented.
3786 *
3787 * Parse and evaluate an Equality expression, then push the result on the stack
3788 *
3789 */
3790void
3791xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3792 xmlXPathEvalRelationalExpr(ctxt);
3793 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003794 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003795 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003796 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003797 int eq, equal;
3798
3799 if (CUR == '=') eq = 1;
3800 else eq = 0;
3801 NEXT;
3802 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003803 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003804 xmlXPathEvalRelationalExpr(ctxt);
3805 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003806 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003807 if (eq) res = xmlXPathNewBoolean(equal);
3808 else res = xmlXPathNewBoolean(!equal);
3809 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003810 }
3811}
3812
3813/**
3814 * xmlXPathEvalAndExpr:
3815 * @ctxt: the XPath Parser context
3816 *
3817 * [22] AndExpr ::= EqualityExpr
3818 * | AndExpr 'and' EqualityExpr
3819 *
3820 * Parse and evaluate an AND expression, then push the result on the stack
3821 *
3822 */
3823void
3824xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3825 xmlXPathEvalEqualityExpr(ctxt);
3826 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003827 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003828 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3829 xmlXPathObjectPtr arg1, arg2;
3830
3831 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003832 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003833 xmlXPathEvalEqualityExpr(ctxt);
3834 CHECK_ERROR;
3835 arg2 = valuePop(ctxt);
3836 arg1 = valuePop(ctxt);
3837 arg1->boolval &= arg2->boolval;
3838 valuePush(ctxt, arg1);
3839 xmlXPathFreeObject(arg2);
3840 }
3841}
3842
3843/**
3844 * xmlXPathEvalExpr:
3845 * @ctxt: the XPath Parser context
3846 *
3847 * [14] Expr ::= OrExpr
3848 * [21] OrExpr ::= AndExpr
3849 * | OrExpr 'or' AndExpr
3850 *
3851 * Parse and evaluate an expression, then push the result on the stack
3852 *
3853 */
3854void
3855xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3856 xmlXPathEvalAndExpr(ctxt);
3857 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003858 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003859 while ((CUR == 'o') && (NXT(1) == 'r')) {
3860 xmlXPathObjectPtr arg1, arg2;
3861
3862 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003863 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003864 xmlXPathEvalAndExpr(ctxt);
3865 CHECK_ERROR;
3866 arg2 = valuePop(ctxt);
3867 arg1 = valuePop(ctxt);
3868 arg1->boolval |= arg2->boolval;
3869 valuePush(ctxt, arg1);
3870 xmlXPathFreeObject(arg2);
3871 }
3872}
3873
3874/**
3875 * xmlXPathEvaluatePredicateResult:
3876 * @ctxt: the XPath Parser context
3877 * @res: the Predicate Expression evaluation result
3878 * @index: index of the current node in the current list
3879 *
3880 * Evaluate a predicate result for the current node.
3881 * A PredicateExpr is evaluated by evaluating the Expr and converting
3882 * the result to a boolean. If the result is a number, the result will
3883 * be converted to true if the number is equal to the position of the
3884 * context node in the context node list (as returned by the position
3885 * function) and will be converted to false otherwise; if the result
3886 * is not a number, then the result will be converted as if by a call
3887 * to the boolean function.
3888 */
3889int
3890xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3891 xmlXPathObjectPtr res, int index) {
3892 if (res == NULL) return(0);
3893 switch (res->type) {
3894 case XPATH_BOOLEAN:
3895 return(res->boolval);
3896 case XPATH_NUMBER:
3897 return(res->floatval == index);
3898 case XPATH_NODESET:
3899 return(res->nodesetval->nodeNr != 0);
3900 case XPATH_STRING:
3901 return((res->stringval != NULL) &&
3902 (xmlStrlen(res->stringval) != 0));
3903 default:
3904 STRANGE
3905 }
3906 return(0);
3907}
3908
3909/**
3910 * xmlXPathEvalPredicate:
3911 * @ctxt: the XPath Parser context
3912 *
3913 * [8] Predicate ::= '[' PredicateExpr ']'
3914 * [9] PredicateExpr ::= Expr
3915 *
3916 * Parse and evaluate a predicate for all the elements of the
3917 * current node list. Then refine the list by removing all
3918 * nodes where the predicate is false.
3919 */
3920void
3921xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003922 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003923 xmlXPathObjectPtr res;
3924 xmlNodeSetPtr newset = NULL;
3925 int i;
3926
Daniel Veillard00fdf371999-10-08 09:40:39 +00003927 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003928 if (CUR != '[') {
3929 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3930 }
3931 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003932 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003933 if ((ctxt->context->nodelist == NULL) ||
3934 (ctxt->context->nodelist->nodeNr == 0)) {
3935 ctxt->context->node = NULL;
3936 xmlXPathEvalExpr(ctxt);
3937 CHECK_ERROR;
3938 res = valuePop(ctxt);
3939 if (res != NULL)
3940 xmlXPathFreeObject(res);
3941 } else {
3942 cur = ctxt->cur;
3943 newset = xmlXPathNodeSetCreate(NULL);
3944 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3945 ctxt->cur = cur;
3946 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3947 xmlXPathEvalExpr(ctxt);
3948 CHECK_ERROR;
3949 res = valuePop(ctxt);
3950 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3951 xmlXPathNodeSetAdd(newset,
3952 ctxt->context->nodelist->nodeTab[i]);
3953 if (res != NULL)
3954 xmlXPathFreeObject(res);
3955 }
3956 if (ctxt->context->nodelist != NULL)
3957 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3958 ctxt->context->nodelist = newset;
3959 ctxt->context->node = NULL;
3960 }
3961 if (CUR != ']') {
3962 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3963 }
3964 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003965 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003966#ifdef DEBUG_STEP
3967 fprintf(xmlXPathDebug, "After predicate : ");
3968 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3969#endif
3970}
3971
3972/**
3973 * xmlXPathEvalBasis:
3974 * @ctxt: the XPath Parser context
3975 *
3976 * [5] Basis ::= AxisName '::' NodeTest
3977 * | AbbreviatedBasis
3978 * [13] AbbreviatedBasis ::= NodeTest
3979 * | '@' NodeTest
3980 * [7] NodeTest ::= WildcardName
3981 * | NodeType '(' ')'
3982 * | 'processing-instruction' '(' Literal ')'
3983 * [37] WildcardName ::= '*'
3984 * | NCName ':' '*'
3985 * | QName
3986 *
3987 * Evaluate one step in a Location Path
3988 */
3989void
3990xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003991 xmlChar *name = NULL;
3992 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003993 int type = 0;
3994 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
3995 int nodetest = NODE_TEST_NONE;
3996 int nodetype = 0;
3997 xmlNodeSetPtr newset = NULL;
3998
3999 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004000 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004001 axis = AXIS_ATTRIBUTE;
4002 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004003 } else if (CUR == '*') {
4004 NEXT;
4005 nodetest = NODE_TEST_ALL;
4006 } else {
4007 name = xmlXPathParseNCName(ctxt);
4008 if (name == NULL) {
4009 ERROR(XPATH_EXPR_ERROR);
4010 }
4011 type = xmlXPathGetNameType(ctxt, name);
4012 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004013 case IS_FUNCTION: {
4014 xmlXPathFunction func;
4015 int nbargs = 0;
4016 xmlXPathObjectPtr top;
4017
4018 top = ctxt->value;
4019 func = xmlXPathIsFunction(ctxt, name);
4020 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004021 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004022 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4023 }
4024#ifdef DEBUG_EXPR
4025 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4026#endif
4027
4028 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004029 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004030 ERROR(XPATH_EXPR_ERROR);
4031 }
4032 NEXT;
4033
4034 while (CUR != ')') {
4035 xmlXPathEvalExpr(ctxt);
4036 nbargs++;
4037 if (CUR == ')') break;
4038 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004039 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004040 ERROR(XPATH_EXPR_ERROR);
4041 }
4042 NEXT;
4043 }
4044 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004045 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004046 func(ctxt, nbargs);
4047 if ((ctxt->value != top) &&
4048 (ctxt->value != NULL) &&
4049 (ctxt->value->type == XPATH_NODESET)) {
4050 xmlXPathObjectPtr cur;
4051
4052 cur = valuePop(ctxt);
4053 ctxt->context->nodelist = cur->nodesetval;
4054 ctxt->context->node = NULL;
4055 cur->nodesetval = NULL;
4056 xmlXPathFreeObject(cur);
4057 }
4058 return;
4059 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004060 /*
4061 * Simple case: no axis seach all given node types.
4062 */
4063 case NODE_TYPE_COMMENT:
4064 if ((CUR != '(') || (NXT(1) != ')')) break;
4065 SKIP(2);
4066 nodetest = NODE_TEST_TYPE;
4067 nodetype = XML_COMMENT_NODE;
4068 goto search_nodes;
4069 case NODE_TYPE_TEXT:
4070 if ((CUR != '(') || (NXT(1) != ')')) break;
4071 SKIP(2);
4072 nodetest = NODE_TEST_TYPE;
4073 nodetype = XML_TEXT_NODE;
4074 goto search_nodes;
4075 case NODE_TYPE_NODE:
4076 if ((CUR != '(') || (NXT(1) != ')')) {
4077 nodetest = NODE_TEST_NAME;
4078 break;
4079 }
4080 SKIP(2);
4081 nodetest = NODE_TEST_TYPE;
4082 nodetype = XML_ELEMENT_NODE;
4083 goto search_nodes;
4084 case NODE_TYPE_PI:
4085 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004086 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004087 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004088 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004089 xmlXPathObjectPtr cur;
4090
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004091 /*
4092 * Specific case: search a PI by name.
4093 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004094 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004095 nodetest = NODE_TEST_PI;
4096 xmlXPathEvalLiteral(ctxt);
4097 CHECK_ERROR;
4098 if (CUR != ')')
4099 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004100 NEXT;
4101 xmlXPathStringFunction(ctxt, 1);
4102 CHECK_ERROR;
4103 cur = valuePop(ctxt);
4104 name = xmlStrdup(cur->stringval);
4105 xmlXPathFreeObject(cur);
4106 } else
4107 SKIP(2);
4108 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004109 goto search_nodes;
4110
4111 /*
4112 * Handling of the compund form: got the axis.
4113 */
4114 case AXIS_ANCESTOR:
4115 case AXIS_ANCESTOR_OR_SELF:
4116 case AXIS_ATTRIBUTE:
4117 case AXIS_CHILD:
4118 case AXIS_DESCENDANT:
4119 case AXIS_DESCENDANT_OR_SELF:
4120 case AXIS_FOLLOWING:
4121 case AXIS_FOLLOWING_SIBLING:
4122 case AXIS_NAMESPACE:
4123 case AXIS_PARENT:
4124 case AXIS_PRECEDING:
4125 case AXIS_PRECEDING_SIBLING:
4126 case AXIS_SELF:
4127 if ((CUR != ':') || (NXT(1) != ':')) {
4128 nodetest = NODE_TEST_NAME;
4129 break;
4130 }
4131 SKIP(2);
4132 axis = type;
4133 break;
4134
4135 /*
4136 * Default: abbreviated syntax the axis is AXIS_CHILD
4137 */
4138 default:
4139 nodetest = NODE_TEST_NAME;
4140 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004141parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004142 if (nodetest == NODE_TEST_NONE) {
4143 if (CUR == '*') {
4144 NEXT;
4145 nodetest = NODE_TEST_ALL;
4146 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004147 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004148 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004149 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004150 if (name == NULL) {
4151 ERROR(XPATH_EXPR_ERROR);
4152 }
4153 type = xmlXPathGetNameType(ctxt, name);
4154 switch (type) {
4155 /*
4156 * Simple case: no axis seach all given node types.
4157 */
4158 case NODE_TYPE_COMMENT:
4159 if ((CUR != '(') || (NXT(1) != ')')) break;
4160 SKIP(2);
4161 nodetest = NODE_TEST_TYPE;
4162 nodetype = XML_COMMENT_NODE;
4163 goto search_nodes;
4164 case NODE_TYPE_TEXT:
4165 if ((CUR != '(') || (NXT(1) != ')')) break;
4166 SKIP(2);
4167 nodetest = NODE_TEST_TYPE;
4168 nodetype = XML_TEXT_NODE;
4169 goto search_nodes;
4170 case NODE_TYPE_NODE:
4171 if ((CUR != '(') || (NXT(1) != ')')) {
4172 nodetest = NODE_TEST_NAME;
4173 break;
4174 }
4175 SKIP(2);
4176 nodetest = NODE_TEST_TYPE;
4177 nodetype = XML_ELEMENT_NODE;
4178 goto search_nodes;
4179 case NODE_TYPE_PI:
4180 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004181 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004182 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004183 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004184 xmlXPathObjectPtr cur;
4185
Daniel Veillardb05deb71999-08-10 19:04:08 +00004186 /*
4187 * Specific case: search a PI by name.
4188 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004189 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004190 nodetest = NODE_TEST_PI;
4191 xmlXPathEvalLiteral(ctxt);
4192 CHECK_ERROR;
4193 if (CUR != ')')
4194 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004195 NEXT;
4196 xmlXPathStringFunction(ctxt, 1);
4197 CHECK_ERROR;
4198 cur = valuePop(ctxt);
4199 name = xmlStrdup(cur->stringval);
4200 xmlXPathFreeObject(cur);
4201 } else
4202 SKIP(2);
4203 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004204 goto search_nodes;
4205 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004206 nodetest = NODE_TEST_NAME;
4207 }
4208 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4209 NEXT;
4210 prefix = name;
4211 if (CUR == '*') {
4212 NEXT;
4213 nodetest = NODE_TEST_ALL;
4214 } else
4215 name = xmlXPathParseNCName(ctxt);
4216 } else if (name == NULL)
4217 ERROR(XPATH_EXPR_ERROR);
4218 }
4219
4220search_nodes:
4221
4222#ifdef DEBUG_STEP
4223 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4224#endif
4225 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4226 prefix, name);
4227 if (ctxt->context->nodelist != NULL)
4228 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4229 ctxt->context->nodelist = newset;
4230 ctxt->context->node = NULL;
4231#ifdef DEBUG_STEP
4232 fprintf(xmlXPathDebug, "Basis : ");
4233 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4234#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004235 if (name != NULL) xmlFree(name);
4236 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004237}
4238
4239/**
4240 * xmlXPathEvalStep:
4241 * @ctxt: the XPath Parser context
4242 *
4243 * [4] Step ::= Basis Predicate*
4244 * | AbbreviatedStep
4245 * [12] AbbreviatedStep ::= '.'
4246 * | '..'
4247 *
4248 * Evaluate one step in a Location Path
4249 * A location step of . is short for self::node(). This is
4250 * particularly useful in conjunction with //. For example, the
4251 * location path .//para is short for
4252 * self::node()/descendant-or-self::node()/child::para
4253 * and so will select all para descendant elements of the context
4254 * node.
4255 * Similarly, a location step of .. is short for parent::node().
4256 * For example, ../title is short for parent::node()/child::title
4257 * and so will select the title children of the parent of the context
4258 * node.
4259 */
4260void
4261xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4262 xmlNodeSetPtr newset = NULL;
4263
Daniel Veillard00fdf371999-10-08 09:40:39 +00004264 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004265 if ((CUR == '.') && (NXT(1) == '.')) {
4266 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004267 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004268 if (ctxt->context->nodelist == NULL) {
4269 STRANGE
4270 xmlXPathRoot(ctxt);
4271 }
4272 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4273 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4274 if (ctxt->context->nodelist != NULL)
4275 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4276 ctxt->context->nodelist = newset;
4277 ctxt->context->node = NULL;
4278 } else if (CUR == '.') {
4279 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004280 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004281 } else {
4282 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004283 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004284 while (CUR == '[') {
4285 xmlXPathEvalPredicate(ctxt);
4286 }
4287 }
4288#ifdef DEBUG_STEP
4289 fprintf(xmlXPathDebug, "Step : ");
4290 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4291#endif
4292}
4293
4294/**
4295 * xmlXPathEvalRelativeLocationPath:
4296 * @ctxt: the XPath Parser context
4297 *
4298 * [3] RelativeLocationPath ::= Step
4299 * | RelativeLocationPath '/' Step
4300 * | AbbreviatedRelativeLocationPath
4301 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4302 *
4303 */
4304void
4305xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4306 xmlNodeSetPtr newset = NULL;
4307
Daniel Veillard00fdf371999-10-08 09:40:39 +00004308 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004309 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004310 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004311 while (CUR == '/') {
4312 if ((CUR == '/') && (NXT(1) == '/')) {
4313 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004314 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004315 if (ctxt->context->nodelist == NULL) {
4316 STRANGE
4317 xmlXPathRoot(ctxt);
4318 }
4319 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4320 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4321 if (ctxt->context->nodelist != NULL)
4322 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4323 ctxt->context->nodelist = newset;
4324 ctxt->context->node = NULL;
4325 xmlXPathEvalStep(ctxt);
4326 } else if (CUR == '/') {
4327 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004328 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004329 xmlXPathEvalStep(ctxt);
4330 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004331 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004332 }
4333}
4334
4335/**
4336 * xmlXPathEvalLocationPath:
4337 * @ctxt: the XPath Parser context
4338 *
4339 * [1] LocationPath ::= RelativeLocationPath
4340 * | AbsoluteLocationPath
4341 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4342 * | AbbreviatedAbsoluteLocationPath
4343 * [10] AbbreviatedAbsoluteLocationPath ::=
4344 * '//' RelativeLocationPath
4345 *
4346 * // is short for /descendant-or-self::node()/. For example,
4347 * //para is short for /descendant-or-self::node()/child::para and
4348 * so will select any para element in the document (even a para element
4349 * that is a document element will be selected by //para since the
4350 * document element node is a child of the root node); div//para is
4351 * short for div/descendant-or-self::node()/child::para and so will
4352 * select all para descendants of div children.
4353 */
4354void
4355xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4356 xmlNodeSetPtr newset = NULL;
4357
Daniel Veillard00fdf371999-10-08 09:40:39 +00004358 SKIP_BLANKS;
4359 if (CUR != '/') {
4360 xmlXPathEvalRelativeLocationPath(ctxt);
4361 } else {
4362 while (CUR == '/') {
4363 if ((CUR == '/') && (NXT(1) == '/')) {
4364 SKIP(2);
4365 SKIP_BLANKS;
4366 if (ctxt->context->nodelist == NULL)
4367 xmlXPathRoot(ctxt);
4368 newset = xmlXPathNodeCollectAndTest(ctxt,
4369 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4370 XML_ELEMENT_NODE, NULL, NULL);
4371 if (ctxt->context->nodelist != NULL)
4372 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4373 ctxt->context->nodelist = newset;
4374 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004375 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004376 } else if (CUR == '/') {
4377 NEXT;
4378 SKIP_BLANKS;
4379 xmlXPathRoot(ctxt);
4380 if (CUR != 0)
4381 xmlXPathEvalRelativeLocationPath(ctxt);
4382 } else {
4383 xmlXPathEvalRelativeLocationPath(ctxt);
4384 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004385 }
4386 }
4387}
4388
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004389/**
4390 * xmlXPathEval:
4391 * @str: the XPath expression
4392 * @ctxt: the XPath context
4393 *
4394 * Evaluate the XPath Location Path in the given context.
4395 *
4396 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4397 * the caller has to free the object.
4398 */
4399xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004400xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004401 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004402 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004403
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004404 xmlXPathInit();
4405
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004406 CHECK_CONTEXT
4407
4408 if (xmlXPathDebug == NULL)
4409 xmlXPathDebug = stderr;
4410 pctxt = xmlXPathNewParserContext(str, ctxt);
4411 xmlXPathEvalLocationPath(pctxt);
4412
Daniel Veillardb96e6431999-08-29 21:02:19 +00004413 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004414 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004415 tmp = valuePop(pctxt);
4416 if (tmp != NULL);
4417 xmlXPathFreeObject(tmp);
4418 } while (tmp != NULL);
4419 if (res == NULL)
4420 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004421 xmlXPathFreeParserContext(pctxt);
4422 return(res);
4423}
4424
4425/**
4426 * xmlXPathEvalExpression:
4427 * @str: the XPath expression
4428 * @ctxt: the XPath context
4429 *
4430 * Evaluate the XPath expression in the given context.
4431 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004432 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004433 * the caller has to free the object.
4434 */
4435xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004436xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004437 xmlXPathParserContextPtr pctxt;
4438 xmlXPathObjectPtr res, tmp;
4439
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004440 xmlXPathInit();
4441
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004442 CHECK_CONTEXT
4443
4444 if (xmlXPathDebug == NULL)
4445 xmlXPathDebug = stderr;
4446 pctxt = xmlXPathNewParserContext(str, ctxt);
4447 xmlXPathEvalExpr(pctxt);
4448
4449 res = valuePop(pctxt);
4450 do {
4451 tmp = valuePop(pctxt);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004452 if (tmp != NULL);
4453 xmlXPathFreeObject(tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004454 } while (tmp != NULL);
4455 xmlXPathFreeParserContext(pctxt);
4456 return(res);
4457}
4458