blob: f646e9f7ef0016bfb466b76a9400b2efa7b5f9a6 [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer.
5 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
17#define HAVE_FCNTL_H
18#include <io.h>
19#else
20#include "config.h"
21#endif
22
23#include <stdio.h>
24#include <string.h>
25
26#ifdef HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000029#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000030#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000031#endif
32#ifdef HAVE_MATH_H
33#include <float.h>
34#endif
35#ifdef HAVE_IEEEFP_H
36#include <ieeefp.h>
37#endif
38#ifdef HAVE_NAN_H
39#include <nan.h>
40#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000041#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000042#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000043#endif
44
Daniel Veillard6454aec1999-09-02 22:04:43 +000045#include "xmlmemory.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000046#include "tree.h"
Daniel Veillardb96e6431999-08-29 21:02:19 +000047#include "valid.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000048#include "xpath.h"
49#include "parserInternals.h"
50
51/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000052 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000053 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000054 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000055double xmlXPathNAN = 0;
56double xmlXPathPINF = 1;
57double xmlXPathMINF = -1;
58
Daniel Veillardb05deb71999-08-10 19:04:08 +000059#ifndef isinf
60#ifndef HAVE_ISINF
61
62#if HAVE_FPCLASS
63
64int isinf(double d) {
65 fpclass_t type = fpclass(d);
66 switch (type) {
67 case FP_NINF:
68 return(-1);
69 case FP_PINF:
70 return(1);
71 default:
72 return(0);
73 }
74 return(0);
75}
76
77#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
78
79#if HAVE_FP_CLASS_H
80#include <fp_class.h>
81#endif
82
83int isinf(double d) {
84#if HAVE_FP_CLASS
85 int fpclass = fp_class(d);
86#else
87 int fpclass = fp_class_d(d);
88#endif
89 if (fpclass == FP_POS_INF)
90 return(1);
91 if (fpclass == FP_NEG_INF)
92 return(-1);
93 return(0);
94}
95
96#elif defined(HAVE_CLASS)
97
98int isinf(double d) {
99 int fpclass = class(d);
100 if (fpclass == FP_PLUS_INF)
101 return(1);
102 if (fpclass == FP_MINUS_INF)
103 return(-1);
104 return(0);
105}
106#elif defined(finite) || defined(HAVE_FINITE)
107int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000108#elif defined(HUGE_VAL)
109static int isinf(double x)
110{
111 if (x == HUGE_VAL)
112 return(1);
113 if (x == -HUGE_VAL)
114 return(-1);
115 return(0);
116}
117#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000118
119#endif /* ! HAVE_ISINF */
120#endif /* ! defined(isinf) */
121
122#ifndef isnan
123#ifndef HAVE_ISNAN
124
125#ifdef HAVE_ISNAND
126#define isnan(f) isnand(f)
127#endif /* HAVE_iSNAND */
128
129#endif /* ! HAVE_iSNAN */
130#endif /* ! defined(isnan) */
131
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000132/**
133 * xmlXPathInit:
134 *
135 * Initialize the XPath environment
136 */
137void
138xmlXPathInit(void) {
139 static int initialized = 0;
140
141 if (initialized) return;
142
143 xmlXPathNAN = 0;
144 xmlXPathNAN /= 0;
145
146 xmlXPathPINF = 1;
147 xmlXPathPINF /= 0;
148
149 xmlXPathMINF = -1;
150 xmlXPathMINF /= 0;
151
152 initialized = 1;
153}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000154
155/* #define DEBUG */
156/* #define DEBUG_STEP */
157/* #define DEBUG_EXPR */
158
159FILE *xmlXPathDebug = NULL;
160
161#define TODO \
162 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
163 __FILE__, __LINE__);
164
165#define STRANGE \
166 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
167 __FILE__, __LINE__);
168
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000169double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000170void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000171
172/************************************************************************
173 * *
174 * Parser stacks related functions and macros *
175 * *
176 ************************************************************************/
177
178/*
179 * Generic function for accessing stacks in the Parser Context
180 */
181
182#define PUSH_AND_POP(type, name) \
183extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
184 if (ctxt->name##Nr >= ctxt->name##Max) { \
185 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000186 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000187 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
188 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000189 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000190 exit(1); \
191 } \
192 } \
193 ctxt->name##Tab[ctxt->name##Nr] = value; \
194 ctxt->name = value; \
195 return(ctxt->name##Nr++); \
196} \
197extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
198 type ret; \
199 if (ctxt->name##Nr <= 0) return(0); \
200 ctxt->name##Nr--; \
201 if (ctxt->name##Nr > 0) \
202 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
203 else \
204 ctxt->name = NULL; \
205 ret = ctxt->name##Tab[ctxt->name##Nr]; \
206 ctxt->name##Tab[ctxt->name##Nr] = 0; \
207 return(ret); \
208} \
209
210PUSH_AND_POP(xmlXPathObjectPtr, value)
211
212/*
213 * Macros for accessing the content. Those should be used only by the parser,
214 * and not exported.
215 *
216 * Dirty macros, i.e. one need to make assumption on the context to use them
217 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000218 * CUR_PTR return the current pointer to the xmlChar to be parsed.
219 * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000220 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
221 * in UNICODE mode. This should be used internally by the parser
222 * only to compare to ASCII values otherwise it would break when
223 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000224 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000225 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000226 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000227 * strings within the parser.
228 * CURRENT Returns the current char value, with the full decoding of
229 * UTF-8 if we are using this mode. It returns an int.
230 * NEXT Skip to the next character, this does the proper decoding
231 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000232 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000233 */
234
235#define CUR (*ctxt->cur)
236#define SKIP(val) ctxt->cur += (val)
237#define NXT(val) ctxt->cur[(val)]
238#define CUR_PTR ctxt->cur
239
240#define SKIP_BLANKS \
241 while (IS_BLANK(*(ctxt->cur))) NEXT
242
243#ifndef USE_UTF_8
244#define CURRENT (*ctxt->cur)
245#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
246#else
247#endif
248
249/************************************************************************
250 * *
251 * Error handling routines *
252 * *
253 ************************************************************************/
254
255#define XPATH_EXPRESSION_OK 0
256#define XPATH_NUMBER_ERROR 1
257#define XPATH_UNFINISHED_LITERAL_ERROR 2
258#define XPATH_START_LITERAL_ERROR 3
259#define XPATH_VARIABLE_REF_ERROR 4
260#define XPATH_UNDEF_VARIABLE_ERROR 5
261#define XPATH_INVALID_PREDICATE_ERROR 6
262#define XPATH_EXPR_ERROR 7
263#define XPATH_UNCLOSED_ERROR 8
264#define XPATH_UNKNOWN_FUNC_ERROR 9
265#define XPATH_INVALID_OPERAND 10
266#define XPATH_INVALID_TYPE 11
267#define XPATH_INVALID_ARITY 12
268
269const char *xmlXPathErrorMessages[] = {
270 "Ok",
271 "Number encoding",
272 "Unfinished litteral",
273 "Start of litteral",
274 "Expected $ for variable reference",
275 "Undefined variable",
276 "Invalid predicate",
277 "Invalid expression",
278 "Missing closing curly brace",
279 "Unregistered function",
280 "Invalid operand",
281 "Invalid type",
282 "Invalid number of arguments",
283};
284
285/**
286 * xmlXPathError:
287 * @ctxt: the XPath Parser context
288 * @file: the file name
289 * @line: the line number
290 * @no: the error number
291 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000292 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000293 *
294 * Returns the newly created object.
295 */
296void
297xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
298 int line, int no) {
299 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000300 const xmlChar *cur;
301 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000302
303 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
304 xmlXPathErrorMessages[no]);
305
306 cur = ctxt->cur;
307 base = ctxt->base;
308 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
309 cur--;
310 }
311 n = 0;
312 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
313 cur--;
314 if ((*cur == '\n') || (*cur == '\r')) cur++;
315 base = cur;
316 n = 0;
317 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
318 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
319 n++;
320 }
321 fprintf(xmlXPathDebug, "\n");
322 cur = ctxt->cur;
323 while ((*cur == '\n') || (*cur == '\r'))
324 cur--;
325 n = 0;
326 while ((cur != base) && (n++ < 80)) {
327 fprintf(xmlXPathDebug, " ");
328 base++;
329 }
330 fprintf(xmlXPathDebug,"^\n");
331}
332
333#define CHECK_ERROR \
334 if (ctxt->error != XPATH_EXPRESSION_OK) return
335
336#define ERROR(X) \
337 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
338 ctxt->error = (X); return; }
339
Daniel Veillard991e63d1999-08-15 23:32:28 +0000340#define ERROR0(X) \
341 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
342 ctxt->error = (X); return(0); }
343
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000344#define CHECK_TYPE(typeval) \
345 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
346 ERROR(XPATH_INVALID_TYPE) \
347
348
349/************************************************************************
350 * *
351 * Routines to handle NodeSets *
352 * *
353 ************************************************************************/
354
355#define XML_NODESET_DEFAULT 10
356/**
357 * xmlXPathNodeSetCreate:
358 * @val: an initial xmlNodePtr, or NULL
359 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000360 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000361 *
362 * Returns the newly created object.
363 */
364xmlNodeSetPtr
365xmlXPathNodeSetCreate(xmlNodePtr val) {
366 xmlNodeSetPtr ret;
367
Daniel Veillard6454aec1999-09-02 22:04:43 +0000368 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000369 if (ret == NULL) {
370 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
371 return(NULL);
372 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000373 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000374 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000375 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000376 sizeof(xmlNodePtr));
377 if (ret->nodeTab == NULL) {
378 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
379 return(NULL);
380 }
381 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000382 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000383 ret->nodeMax = XML_NODESET_DEFAULT;
384 ret->nodeTab[ret->nodeNr++] = val;
385 }
386 return(ret);
387}
388
389/**
390 * xmlXPathNodeSetAdd:
391 * @cur: the initial node set
392 * @val: a new xmlNodePtr
393 *
394 * add a new xmlNodePtr ot an existing NodeSet
395 */
396void
397xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
398 int i;
399
400 if (val == NULL) return;
401
402 /*
403 * check against doublons
404 */
405 for (i = 0;i < cur->nodeNr;i++)
406 if (cur->nodeTab[i] == val) return;
407
408 /*
409 * grow the nodeTab if needed
410 */
411 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000412 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000413 sizeof(xmlNodePtr));
414 if (cur->nodeTab == NULL) {
415 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
416 return;
417 }
418 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000419 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000420 cur->nodeMax = XML_NODESET_DEFAULT;
421 } else if (cur->nodeNr == cur->nodeMax) {
422 xmlNodePtr *temp;
423
424 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000425 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000426 sizeof(xmlNodePtr));
427 if (temp == NULL) {
428 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
429 return;
430 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000431 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000432 }
433 cur->nodeTab[cur->nodeNr++] = val;
434}
435
436/**
437 * xmlXPathNodeSetMerge:
438 * @val1: the first NodeSet
439 * @val2: the second NodeSet
440 *
441 * Merges two nodesets, all nodes from @val2 are added to @val1
442 *
443 * Returns val1 once extended or NULL in case of error.
444 */
445xmlNodeSetPtr
446xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
447 int i;
448
449 if (val1 == NULL) return(NULL);
450 if (val2 == NULL) return(val1);
451
452 /*
453 * !!!!! this can be optimized a lot, knowing that both
454 * val1 and val2 already have unicity of their values.
455 */
456
457 for (i = 0;i < val2->nodeNr;i++)
458 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
459
460 return(val1);
461}
462
463/**
464 * xmlXPathNodeSetDel:
465 * @cur: the initial node set
466 * @val: an xmlNodePtr
467 *
468 * Removes an xmlNodePtr from an existing NodeSet
469 */
470void
471xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
472 int i;
473
474 if (cur == NULL) return;
475 if (val == NULL) return;
476
477 /*
478 * check against doublons
479 */
480 for (i = 0;i < cur->nodeNr;i++)
481 if (cur->nodeTab[i] == val) break;
482
483 if (i >= cur->nodeNr) {
484#ifdef DEBUG
485 fprintf(xmlXPathDebug,
486 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
487 val->name);
488#endif
489 return;
490 }
491 cur->nodeNr--;
492 for (;i < cur->nodeNr;i++)
493 cur->nodeTab[i] = cur->nodeTab[i + 1];
494 cur->nodeTab[cur->nodeNr] = NULL;
495}
496
497/**
498 * xmlXPathNodeSetRemove:
499 * @cur: the initial node set
500 * @val: the index to remove
501 *
502 * Removes an entry from an existing NodeSet list.
503 */
504void
505xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
506 if (cur == NULL) return;
507 if (val >= cur->nodeNr) return;
508 cur->nodeNr--;
509 for (;val < cur->nodeNr;val++)
510 cur->nodeTab[val] = cur->nodeTab[val + 1];
511 cur->nodeTab[cur->nodeNr] = NULL;
512}
513
514/**
515 * xmlXPathFreeNodeSet:
516 * @obj: the xmlNodeSetPtr to free
517 *
518 * Free the NodeSet compound (not the actual nodes !).
519 */
520void
521xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
522 if (obj == NULL) return;
523 if (obj->nodeTab != NULL) {
524#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000525 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000526#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000527 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000528 }
529#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000530 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000531#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000532 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000533}
534
Daniel Veillardb96e6431999-08-29 21:02:19 +0000535#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000536/**
537 * xmlXPathDebugNodeSet:
538 * @output: a FILE * for the output
539 * @obj: the xmlNodeSetPtr to free
540 *
541 * Quick display of a NodeSet
542 */
543void
544xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
545 int i;
546
547 if (output == NULL) output = xmlXPathDebug;
548 if (obj == NULL) {
549 fprintf(output, "NodeSet == NULL !\n");
550 return;
551 }
552 if (obj->nodeNr == 0) {
553 fprintf(output, "NodeSet is empty\n");
554 return;
555 }
556 if (obj->nodeTab == NULL) {
557 fprintf(output, " nodeTab == NULL !\n");
558 return;
559 }
560 for (i = 0; i < obj->nodeNr; i++) {
561 if (obj->nodeTab[i] == NULL) {
562 fprintf(output, " NULL !\n");
563 return;
564 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000565 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
566 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000567 fprintf(output, " /");
568 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000569 fprintf(output, " noname!");
570 else fprintf(output, " %s", obj->nodeTab[i]->name);
571 }
572 fprintf(output, "\n");
573}
574#endif
575
576/************************************************************************
577 * *
578 * Routines to handle Variable *
579 * *
580 * UNIMPLEMENTED CURRENTLY *
581 * *
582 ************************************************************************/
583
584/**
585 * xmlXPathVariablelookup:
586 * @ctxt: the XPath Parser context
587 * @prefix: the variable name namespace if any
588 * @name: the variable name
589 *
590 * Search in the Variable array of the context for the given
591 * variable value.
592 *
593 * UNIMPLEMENTED: always return NULL.
594 *
595 * Returns the value or NULL if not found
596 */
597xmlXPathObjectPtr
598xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000599 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000600 return(NULL);
601}
602
603/************************************************************************
604 * *
605 * Routines to handle Values *
606 * *
607 ************************************************************************/
608
609/* Allocations are terrible, one need to optimize all this !!! */
610
611/**
612 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000613 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000614 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000615 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000616 *
617 * Returns the newly created object.
618 */
619xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000620xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000621 xmlXPathObjectPtr ret;
622
Daniel Veillard6454aec1999-09-02 22:04:43 +0000623 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000624 if (ret == NULL) {
625 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
626 return(NULL);
627 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000628 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000629 ret->type = XPATH_NUMBER;
630 ret->floatval = val;
631 return(ret);
632}
633
634/**
635 * xmlXPathNewBoolean:
636 * @val: the boolean value
637 *
638 * Create a new xmlXPathObjectPtr of type boolean and of value @val
639 *
640 * Returns the newly created object.
641 */
642xmlXPathObjectPtr
643xmlXPathNewBoolean(int val) {
644 xmlXPathObjectPtr ret;
645
Daniel Veillard6454aec1999-09-02 22:04:43 +0000646 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000647 if (ret == NULL) {
648 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
649 return(NULL);
650 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000651 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000652 ret->type = XPATH_BOOLEAN;
653 ret->boolval = (val != 0);
654 return(ret);
655}
656
657/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000658 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000659 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000660 *
661 * Create a new xmlXPathObjectPtr of type string and of value @val
662 *
663 * Returns the newly created object.
664 */
665xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000666xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000667 xmlXPathObjectPtr ret;
668
Daniel Veillard6454aec1999-09-02 22:04:43 +0000669 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000670 if (ret == NULL) {
671 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
672 return(NULL);
673 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000674 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000675 ret->type = XPATH_STRING;
676 ret->stringval = xmlStrdup(val);
677 return(ret);
678}
679
680/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000681 * xmlXPathNewCString:
682 * @val: the char * value
683 *
684 * Create a new xmlXPathObjectPtr of type string and of value @val
685 *
686 * Returns the newly created object.
687 */
688xmlXPathObjectPtr
689xmlXPathNewCString(const char *val) {
690 xmlXPathObjectPtr ret;
691
Daniel Veillard6454aec1999-09-02 22:04:43 +0000692 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000693 if (ret == NULL) {
694 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
695 return(NULL);
696 }
697 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
698 ret->type = XPATH_STRING;
699 ret->stringval = xmlStrdup(BAD_CAST val);
700 return(ret);
701}
702
703/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000704 * xmlXPathNewNodeSet:
705 * @val: the NodePtr value
706 *
707 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
708 * it with the single Node @val
709 *
710 * Returns the newly created object.
711 */
712xmlXPathObjectPtr
713xmlXPathNewNodeSet(xmlNodePtr val) {
714 xmlXPathObjectPtr ret;
715
Daniel Veillard6454aec1999-09-02 22:04:43 +0000716 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000717 if (ret == NULL) {
718 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
719 return(NULL);
720 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000721 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000722 ret->type = XPATH_NODESET;
723 ret->nodesetval = xmlXPathNodeSetCreate(val);
724 return(ret);
725}
726
727/**
728 * xmlXPathNewNodeSetList:
729 * @val: an existing NodeSet
730 *
731 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
732 * it with the Nodeset @val
733 *
734 * Returns the newly created object.
735 */
736xmlXPathObjectPtr
737xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
738 xmlXPathObjectPtr ret;
739
Daniel Veillard6454aec1999-09-02 22:04:43 +0000740 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000741 if (ret == NULL) {
742 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
743 return(NULL);
744 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000745 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000746 ret->type = XPATH_NODESET;
747 ret->nodesetval = val;
748 return(ret);
749}
750
751/**
752 * xmlXPathFreeObject:
753 * @obj: the object to free
754 *
755 * Free up an xmlXPathObjectPtr object.
756 */
757void
758xmlXPathFreeObject(xmlXPathObjectPtr obj) {
759 if (obj == NULL) return;
760 if (obj->nodesetval != NULL)
761 xmlXPathFreeNodeSet(obj->nodesetval);
762 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000763 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000764#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000765 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000766#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000767 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000768}
769
770/************************************************************************
771 * *
772 * Routines to handle XPath contexts *
773 * *
774 ************************************************************************/
775
776/**
777 * xmlXPathNewContext:
778 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000779 *
780 * Create a new xmlXPathContext
781 *
782 * Returns the xmlXPathContext just allocated.
783 */
784xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000785xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000786 xmlXPathContextPtr ret;
787
Daniel Veillard6454aec1999-09-02 22:04:43 +0000788 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000789 if (ret == NULL) {
790 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
791 return(NULL);
792 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000793 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000794 ret->doc = doc;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000795
796 ret->nb_variables = 0;
797 ret->max_variables = 0;
798 ret->variables = NULL;
799
800 ret->nb_types = 0;
801 ret->max_types = 0;
802 ret->types = NULL;
803
804 ret->nb_funcs = 0;
805 ret->max_funcs = 0;
806 ret->funcs = NULL;
807
808 ret->nb_axis = 0;
809 ret->max_axis = 0;
810 ret->axis = NULL;
811
Daniel Veillardb96e6431999-08-29 21:02:19 +0000812 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000813 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000814 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000815 return(ret);
816}
817
818/**
819 * xmlXPathFreeContext:
820 * @ctxt: the context to free
821 *
822 * Free up an xmlXPathContext
823 */
824void
825xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000826 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000827 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000828
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000829#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000830 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000831#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000832 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000833}
834
835/************************************************************************
836 * *
837 * Routines to handle XPath parser contexts *
838 * *
839 ************************************************************************/
840
841#define CHECK_CTXT \
842 if (ctxt == NULL) { \
843 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
844 __FILE__, __LINE__); \
845 } \
846
847
848#define CHECK_CONTEXT \
849 if (ctxt == NULL) { \
850 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
851 __FILE__, __LINE__); \
852 } \
853 if (ctxt->doc == NULL) { \
854 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
855 __FILE__, __LINE__); \
856 } \
857 if (ctxt->doc->root == NULL) { \
858 fprintf(xmlXPathDebug, \
859 "%s:%d Internal error: document without root\n", \
860 __FILE__, __LINE__); \
861 } \
862
863
864/**
865 * xmlXPathNewParserContext:
866 * @str: the XPath expression
867 * @ctxt: the XPath context
868 *
869 * Create a new xmlXPathParserContext
870 *
871 * Returns the xmlXPathParserContext just allocated.
872 */
873xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000874xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000875 xmlXPathParserContextPtr ret;
876
Daniel Veillard6454aec1999-09-02 22:04:43 +0000877 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000878 if (ret == NULL) {
879 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
880 return(NULL);
881 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000882 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000883 ret->cur = ret->base = str;
884 ret->context = ctxt;
885
886 /* Allocate the value stack */
887 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000888 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000889 ret->valueNr = 0;
890 ret->valueMax = 10;
891 ret->value = NULL;
892 return(ret);
893}
894
895/**
896 * xmlXPathFreeParserContext:
897 * @ctxt: the context to free
898 *
899 * Free up an xmlXPathParserContext
900 */
901void
902xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
903 if (ctxt->valueTab != NULL) {
904#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000905 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000906#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000907 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000908 }
909#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000910 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000911#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000912 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000913}
914
915/************************************************************************
916 * *
917 * The implicit core function library *
918 * *
919 ************************************************************************/
920
921/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000922 * Auto-pop and cast to a number
923 */
924void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
925
926#define CHECK_ARITY(x) \
927 if (nargs != (x)) { \
928 ERROR(XPATH_INVALID_ARITY); \
929 } \
930
931
932#define POP_FLOAT \
933 arg = valuePop(ctxt); \
934 if (arg == NULL) { \
935 ERROR(XPATH_INVALID_OPERAND); \
936 } \
937 if (arg->type != XPATH_NUMBER) { \
938 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000939 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000940 arg = valuePop(ctxt); \
941 }
942
943/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000944 * xmlXPathEqualNodeSetString
945 * @arg: the nodeset object argument
946 * @str: the string to compare to.
947 *
948 * Implement the equal operation on XPath objects content: @arg1 == @arg2
949 * If one object to be compared is a node-set and the other is a string,
950 * then the comparison will be true if and only if there is a node in
951 * the node-set such that the result of performing the comparison on the
952 * string-value of the node and the other string is true.
953 *
954 * Returns 0 or 1 depending on the results of the test.
955 */
956int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000957xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000958 int i;
959 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000960 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000961
962 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
963 return(0);
964 ns = arg->nodesetval;
965 for (i = 0;i < ns->nodeNr;i++) {
966 str2 = xmlNodeGetContent(ns->nodeTab[i]);
967 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000968 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000969 return(1);
970 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000971 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000972 }
973 return(0);
974}
975
976/**
977 * xmlXPathEqualNodeSetFloat
978 * @arg: the nodeset object argument
979 * @f: the float to compare to
980 *
981 * Implement the equal operation on XPath objects content: @arg1 == @arg2
982 * If one object to be compared is a node-set and the other is a number,
983 * then the comparison will be true if and only if there is a node in
984 * the node-set such that the result of performing the comparison on the
985 * number to be compared and on the result of converting the string-value
986 * of that node to a number using the number function is true.
987 *
988 * Returns 0 or 1 depending on the results of the test.
989 */
990int
991xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000992 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +0000993
994 if ((arg == NULL) || (arg->type != XPATH_NODESET))
995 return(0);
996
997 if (isnan(f))
998 sprintf(buf, "NaN");
999 else if (isinf(f) > 0)
1000 sprintf(buf, "+Infinity");
1001 else if (isinf(f) < 0)
1002 sprintf(buf, "-Infinity");
1003 else
1004 sprintf(buf, "%0g", f);
1005
Daniel Veillardb96e6431999-08-29 21:02:19 +00001006 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001007}
1008
1009
1010/**
1011 * xmlXPathEqualNodeSets
1012 * @arg1: first nodeset object argument
1013 * @arg2: second nodeset object argument
1014 *
1015 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1016 * If both objects to be compared are node-sets, then the comparison
1017 * will be true if and only if there is a node in the first node-set and
1018 * a node in the second node-set such that the result of performing the
1019 * comparison on the string-values of the two nodes is true.
1020 *
1021 * (needless to say, this is a costly operation)
1022 *
1023 * Returns 0 or 1 depending on the results of the test.
1024 */
1025int
1026xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1027 int i;
1028 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001029 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001030
1031 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1032 return(0);
1033 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1034 return(0);
1035
1036 ns = arg1->nodesetval;
1037 for (i = 0;i < ns->nodeNr;i++) {
1038 str = xmlNodeGetContent(ns->nodeTab[i]);
1039 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001040 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001041 return(1);
1042 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001043 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001044 }
1045 return(0);
1046}
1047
1048/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001049 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001050 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001051 *
1052 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1053 *
1054 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001055 */
1056int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001057xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1058 xmlXPathObjectPtr arg1, arg2;
1059 int ret = 0;
1060
1061 arg1 = valuePop(ctxt);
1062 if (arg1 == NULL)
1063 ERROR0(XPATH_INVALID_OPERAND);
1064
1065 arg2 = valuePop(ctxt);
1066 if (arg2 == NULL) {
1067 xmlXPathFreeObject(arg1);
1068 ERROR0(XPATH_INVALID_OPERAND);
1069 }
1070
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001071 if (arg1 == arg2) {
1072#ifdef DEBUG_EXPR
1073 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1074#endif
1075 return(1);
1076 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001077
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001078 switch (arg1->type) {
1079 case XPATH_UNDEFINED:
1080#ifdef DEBUG_EXPR
1081 fprintf(xmlXPathDebug, "Equal: undefined\n");
1082#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001083 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001084 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001085 switch (arg2->type) {
1086 case XPATH_UNDEFINED:
1087#ifdef DEBUG_EXPR
1088 fprintf(xmlXPathDebug, "Equal: undefined\n");
1089#endif
1090 break;
1091 case XPATH_NODESET:
1092 ret = xmlXPathEqualNodeSets(arg1, arg2);
1093 break;
1094 case XPATH_BOOLEAN:
1095 if ((arg1->nodesetval == NULL) ||
1096 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1097 else
1098 ret = 1;
1099 ret = (ret == arg2->boolval);
1100 break;
1101 case XPATH_NUMBER:
1102 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1103 break;
1104 case XPATH_STRING:
1105 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1106 break;
1107 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001108 break;
1109 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001110 switch (arg2->type) {
1111 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001112#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001113 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001114#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001115 break;
1116 case XPATH_NODESET:
1117 if ((arg2->nodesetval == NULL) ||
1118 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1119 else
1120 ret = 1;
1121 break;
1122 case XPATH_BOOLEAN:
1123#ifdef DEBUG_EXPR
1124 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1125 arg1->boolval, arg2->boolval);
1126#endif
1127 ret = (arg1->boolval == arg2->boolval);
1128 break;
1129 case XPATH_NUMBER:
1130 if (arg2->floatval) ret = 1;
1131 else ret = 0;
1132 ret = (arg1->boolval == ret);
1133 break;
1134 case XPATH_STRING:
1135 if ((arg2->stringval == NULL) ||
1136 (arg2->stringval[0] == 0)) ret = 0;
1137 else
1138 ret = 1;
1139 ret = (arg1->boolval == ret);
1140 break;
1141 }
1142 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001143 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001144 switch (arg2->type) {
1145 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001146#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001147 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001148#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001149 break;
1150 case XPATH_NODESET:
1151 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1152 break;
1153 case XPATH_BOOLEAN:
1154 if (arg1->floatval) ret = 1;
1155 else ret = 0;
1156 ret = (arg2->boolval == ret);
1157 break;
1158 case XPATH_STRING:
1159 valuePush(ctxt, arg2);
1160 xmlXPathNumberFunction(ctxt, 1);
1161 arg2 = valuePop(ctxt);
1162 /* no break on purpose */
1163 case XPATH_NUMBER:
1164 ret = (arg1->floatval == arg2->floatval);
1165 break;
1166 }
1167 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001168 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001169 switch (arg2->type) {
1170 case XPATH_UNDEFINED:
1171#ifdef DEBUG_EXPR
1172 fprintf(xmlXPathDebug, "Equal: undefined\n");
1173#endif
1174 break;
1175 case XPATH_NODESET:
1176 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1177 break;
1178 case XPATH_BOOLEAN:
1179 if ((arg1->stringval == NULL) ||
1180 (arg1->stringval[0] == 0)) ret = 0;
1181 else
1182 ret = 1;
1183 ret = (arg2->boolval == ret);
1184 break;
1185 case XPATH_STRING:
1186 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1187 break;
1188 case XPATH_NUMBER:
1189 valuePush(ctxt, arg1);
1190 xmlXPathNumberFunction(ctxt, 1);
1191 arg1 = valuePop(ctxt);
1192 ret = (arg1->floatval == arg2->floatval);
1193 break;
1194 }
1195 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001196#ifdef DEBUG_EXPR
1197 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
1198 arg1->stringval, arg2->stringval);
1199#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001200 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001201 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001202 xmlXPathFreeObject(arg1);
1203 xmlXPathFreeObject(arg2);
1204 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001205}
1206
1207/**
1208 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001209 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001210 * @inf: less than (1) or greater than (2)
1211 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001212 *
1213 * Implement the compare operation on XPath objects:
1214 * @arg1 < @arg2 (1, 1, ...
1215 * @arg1 <= @arg2 (1, 0, ...
1216 * @arg1 > @arg2 (0, 1, ...
1217 * @arg1 >= @arg2 (0, 0, ...
1218 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001219 * When neither object to be compared is a node-set and the operator is
1220 * <=, <, >=, >, then the objects are compared by converted both objects
1221 * to numbers and comparing the numbers according to IEEE 754. The <
1222 * comparison will be true if and only if the first number is less than the
1223 * second number. The <= comparison will be true if and only if the first
1224 * number is less than or equal to the second number. The > comparison
1225 * will be true if and only if the first number is greater than the second
1226 * number. The >= comparison will be true if and only if the first number
1227 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001228 */
1229int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001230xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1231 int ret = 0;
1232 xmlXPathObjectPtr arg1, arg2;
1233
1234 arg2 = valuePop(ctxt);
1235 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1236 if (arg2 != NULL)
1237 xmlXPathFreeObject(arg2);
1238 ERROR0(XPATH_INVALID_OPERAND);
1239 }
1240
1241 arg1 = valuePop(ctxt);
1242 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1243 if (arg1 != NULL)
1244 xmlXPathFreeObject(arg1);
1245 xmlXPathFreeObject(arg2);
1246 ERROR0(XPATH_INVALID_OPERAND);
1247 }
1248
1249 if (arg1->type != XPATH_NUMBER) {
1250 valuePush(ctxt, arg1);
1251 xmlXPathNumberFunction(ctxt, 1);
1252 arg1 = valuePop(ctxt);
1253 }
1254 if (arg1->type != XPATH_NUMBER) {
1255 xmlXPathFreeObject(arg1);
1256 xmlXPathFreeObject(arg2);
1257 ERROR0(XPATH_INVALID_OPERAND);
1258 }
1259 if (arg2->type != XPATH_NUMBER) {
1260 valuePush(ctxt, arg2);
1261 xmlXPathNumberFunction(ctxt, 1);
1262 arg2 = valuePop(ctxt);
1263 }
1264 if (arg2->type != XPATH_NUMBER) {
1265 xmlXPathFreeObject(arg1);
1266 xmlXPathFreeObject(arg2);
1267 ERROR0(XPATH_INVALID_OPERAND);
1268 }
1269 /*
1270 * Add tests for infinity and nan
1271 * => feedback on 3.4 for Inf and NaN
1272 */
1273 if (inf && strict)
1274 ret = (arg1->floatval < arg2->floatval);
1275 else if (inf && !strict)
1276 ret = (arg1->floatval <= arg2->floatval);
1277 else if (!inf && strict)
1278 ret = (arg1->floatval > arg2->floatval);
1279 else if (!inf && !strict)
1280 ret = (arg1->floatval >= arg2->floatval);
1281 xmlXPathFreeObject(arg1);
1282 xmlXPathFreeObject(arg2);
1283 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001284}
1285
1286/**
1287 * xmlXPathValueFlipSign:
1288 * @ctxt: the XPath Parser context
1289 *
1290 * Implement the unary - operation on an XPath object
1291 * The numeric operators convert their operands to numbers as if
1292 * by calling the number function.
1293 */
1294void
1295xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1296 xmlXPathObjectPtr arg;
1297
1298 POP_FLOAT
1299 arg->floatval = -arg->floatval;
1300 valuePush(ctxt, arg);
1301}
1302
1303/**
1304 * xmlXPathAddValues:
1305 * @ctxt: the XPath Parser context
1306 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001307 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001308 * The numeric operators convert their operands to numbers as if
1309 * by calling the number function.
1310 */
1311void
1312xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1313 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001314 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001315
1316 POP_FLOAT
1317 val = arg->floatval;
1318 xmlXPathFreeObject(arg);
1319
1320 POP_FLOAT
1321 arg->floatval += val;
1322 valuePush(ctxt, arg);
1323}
1324
1325/**
1326 * xmlXPathSubValues:
1327 * @ctxt: the XPath Parser context
1328 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001329 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001330 * The numeric operators convert their operands to numbers as if
1331 * by calling the number function.
1332 */
1333void
1334xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1335 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001336 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001337
1338 POP_FLOAT
1339 val = arg->floatval;
1340 xmlXPathFreeObject(arg);
1341
1342 POP_FLOAT
1343 arg->floatval -= val;
1344 valuePush(ctxt, arg);
1345}
1346
1347/**
1348 * xmlXPathMultValues:
1349 * @ctxt: the XPath Parser context
1350 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001351 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001352 * The numeric operators convert their operands to numbers as if
1353 * by calling the number function.
1354 */
1355void
1356xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1357 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001358 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001359
1360 POP_FLOAT
1361 val = arg->floatval;
1362 xmlXPathFreeObject(arg);
1363
1364 POP_FLOAT
1365 arg->floatval *= val;
1366 valuePush(ctxt, arg);
1367}
1368
1369/**
1370 * xmlXPathDivValues:
1371 * @ctxt: the XPath Parser context
1372 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001373 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001374 * The numeric operators convert their operands to numbers as if
1375 * by calling the number function.
1376 */
1377void
1378xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1379 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001380 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001381
1382 POP_FLOAT
1383 val = arg->floatval;
1384 xmlXPathFreeObject(arg);
1385
1386 POP_FLOAT
1387 arg->floatval /= val;
1388 valuePush(ctxt, arg);
1389}
1390
1391/**
1392 * xmlXPathModValues:
1393 * @ctxt: the XPath Parser context
1394 *
1395 * Implement the div operation on XPath objects: @arg1 / @arg2
1396 * The numeric operators convert their operands to numbers as if
1397 * by calling the number function.
1398 */
1399void
1400xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1401 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001402 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001403
1404 POP_FLOAT
1405 val = arg->floatval;
1406 xmlXPathFreeObject(arg);
1407
1408 POP_FLOAT
1409 arg->floatval /= val;
1410 valuePush(ctxt, arg);
1411}
1412
1413/************************************************************************
1414 * *
1415 * The traversal functions *
1416 * *
1417 ************************************************************************/
1418
1419#define AXIS_ANCESTOR 1
1420#define AXIS_ANCESTOR_OR_SELF 2
1421#define AXIS_ATTRIBUTE 3
1422#define AXIS_CHILD 4
1423#define AXIS_DESCENDANT 5
1424#define AXIS_DESCENDANT_OR_SELF 6
1425#define AXIS_FOLLOWING 7
1426#define AXIS_FOLLOWING_SIBLING 8
1427#define AXIS_NAMESPACE 9
1428#define AXIS_PARENT 10
1429#define AXIS_PRECEDING 11
1430#define AXIS_PRECEDING_SIBLING 12
1431#define AXIS_SELF 13
1432
1433/*
1434 * A traversal function enumerates nodes along an axis.
1435 * Initially it must be called with NULL, and it indicates
1436 * termination on the axis by returning NULL.
1437 */
1438typedef xmlNodePtr (*xmlXPathTraversalFunction)
1439 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1440
1441/**
1442 * mlXPathNextSelf:
1443 * @ctxt: the XPath Parser context
1444 * @cur: the current node in the traversal
1445 *
1446 * Traversal function for the "self" direction
1447 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001448 *
1449 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001450 */
1451xmlNodePtr
1452xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1453 if (cur == NULL)
1454 return(ctxt->context->node);
1455 return(NULL);
1456}
1457
1458/**
1459 * mlXPathNextChild:
1460 * @ctxt: the XPath Parser context
1461 * @cur: the current node in the traversal
1462 *
1463 * Traversal function for the "child" direction
1464 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001465 *
1466 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001467 */
1468xmlNodePtr
1469xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001470 if (cur == NULL) {
1471 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1472 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001473 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001474 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +00001475 if ((ctxt->context->node->type == XML_DOCUMENT_NODE) ||
1476 (ctxt->context->node->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001477 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001478 return(cur->next);
1479}
1480
1481/**
1482 * mlXPathNextDescendant:
1483 * @ctxt: the XPath Parser context
1484 * @cur: the current node in the traversal
1485 *
1486 * Traversal function for the "descendant" direction
1487 * the descendant axis contains the descendants of the context node in document
1488 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001489 *
1490 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001491 */
1492xmlNodePtr
1493xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001494 if (cur == NULL) {
1495 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1496 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001497 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001498 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001499
1500 if (cur->childs != NULL) return(cur->childs);
1501 if (cur->next != NULL) return(cur->next);
1502
1503 do {
1504 cur = cur->parent;
1505 if (cur == NULL) return(NULL);
1506 if (cur == ctxt->context->node) return(NULL);
1507 if (cur->next != NULL) {
1508 cur = cur->next;
1509 return(cur);
1510 }
1511 } while (cur != NULL);
1512 return(cur);
1513}
1514
1515/**
1516 * mlXPathNextDescendantOrSelf:
1517 * @ctxt: the XPath Parser context
1518 * @cur: the current node in the traversal
1519 *
1520 * Traversal function for the "descendant-or-self" direction
1521 * the descendant-or-self axis contains the context node and the descendants
1522 * of the context node in document order; thus the context node is the first
1523 * node on the axis, and the first child of the context node is the second node
1524 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001525 *
1526 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001527 */
1528xmlNodePtr
1529xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1530 if (cur == NULL)
1531 return(ctxt->context->node);
1532
Daniel Veillardb05deb71999-08-10 19:04:08 +00001533 if (cur == (xmlNodePtr) ctxt->context->doc)
1534 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001535 if (cur->childs != NULL) return(cur->childs);
1536 if (cur->next != NULL) return(cur->next);
1537
1538 do {
1539 cur = cur->parent;
1540 if (cur == NULL) return(NULL);
1541 if (cur == ctxt->context->node) return(NULL);
1542 if (cur->next != NULL) {
1543 cur = cur->next;
1544 return(cur);
1545 }
1546 } while (cur != NULL);
1547 return(cur);
1548}
1549
1550/**
1551 * xmlXPathNextParent:
1552 * @ctxt: the XPath Parser context
1553 * @cur: the current node in the traversal
1554 *
1555 * Traversal function for the "parent" direction
1556 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001557 *
1558 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001559 */
1560xmlNodePtr
1561xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1562 /*
1563 * !!!!!!!!!!!!!
1564 * the parent of an attribute or namespace node is the element
1565 * to which the attribute or namespace node is attached
1566 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001567 if (cur == NULL) {
1568 if (ctxt->context->node->parent == NULL)
1569 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001570 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001571 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001572 return(NULL);
1573}
1574
1575/**
1576 * xmlXPathNextAncestor:
1577 * @ctxt: the XPath Parser context
1578 * @cur: the current node in the traversal
1579 *
1580 * Traversal function for the "ancestor" direction
1581 * the ancestor axis contains the ancestors of the context node; the ancestors
1582 * of the context node consist of the parent of context node and the parent's
1583 * parent and so on; the nodes are ordered in reverse document order; thus the
1584 * parent is the first node on the axis, and the parent's parent is the second
1585 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001586 *
1587 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001588 */
1589xmlNodePtr
1590xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1591 /*
1592 * !!!!!!!!!!!!!
1593 * the parent of an attribute or namespace node is the element
1594 * to which the attribute or namespace node is attached
1595 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001596 if (cur == NULL) {
1597 if (ctxt->context->node->parent == NULL)
1598 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001599 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001600 }
1601 if (cur == ctxt->context->doc->root)
1602 return((xmlNodePtr) ctxt->context->doc);
1603 if (cur == (xmlNodePtr) ctxt->context->doc)
1604 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001605 return(cur->parent);
1606}
1607
1608/**
1609 * xmlXPathNextAncestorOrSelf:
1610 * @ctxt: the XPath Parser context
1611 * @cur: the current node in the traversal
1612 *
1613 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001614 * he ancestor-or-self axis contains the context node and ancestors of
1615 * the context node in reverse document order; thus the context node is
1616 * the first node on the axis, and the context node's parent the second;
1617 * parent here is defined the same as with the parent axis.
1618 *
1619 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001620 */
1621xmlNodePtr
1622xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1623 /*
1624 * !!!!!!!!!!!!!
1625 * the parent of an attribute or namespace node is the element
1626 * to which the attribute or namespace node is attached
1627 */
1628 if (cur == NULL)
1629 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001630 if (cur == ctxt->context->doc->root)
1631 return((xmlNodePtr) ctxt->context->doc);
1632 if (cur == (xmlNodePtr) ctxt->context->doc)
1633 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001634 return(cur->parent);
1635}
1636
1637/**
1638 * xmlXPathNextFollowingSibling:
1639 * @ctxt: the XPath Parser context
1640 * @cur: the current node in the traversal
1641 *
1642 * Traversal function for the "following-sibling" direction
1643 * The following-sibling axis contains the following siblings of the context
1644 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001645 *
1646 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001647 */
1648xmlNodePtr
1649xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001650 if (cur == (xmlNodePtr) ctxt->context->doc)
1651 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001652 if (cur == NULL)
1653 return(ctxt->context->node->next);
1654 return(cur->next);
1655}
1656
1657/**
1658 * xmlXPathNextPrecedingSibling:
1659 * @ctxt: the XPath Parser context
1660 * @cur: the current node in the traversal
1661 *
1662 * Traversal function for the "preceding-sibling" direction
1663 * The preceding-sibling axis contains the preceding siblings of the context
1664 * node in reverse document order; the first preceding sibling is first on the
1665 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001666 *
1667 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001668 */
1669xmlNodePtr
1670xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001671 if (cur == (xmlNodePtr) ctxt->context->doc)
1672 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001673 if (cur == NULL)
1674 return(ctxt->context->node->prev);
1675 return(cur->prev);
1676}
1677
1678/**
1679 * xmlXPathNextFollowing:
1680 * @ctxt: the XPath Parser context
1681 * @cur: the current node in the traversal
1682 *
1683 * Traversal function for the "following" direction
1684 * The following axis contains all nodes in the same document as the context
1685 * node that are after the context node in document order, excluding any
1686 * descendants and excluding attribute nodes and namespace nodes; the nodes
1687 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001688 *
1689 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001690 */
1691xmlNodePtr
1692xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001693 if (cur == (xmlNodePtr) ctxt->context->doc)
1694 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001695 if (cur == NULL)
1696 return(ctxt->context->node->next);; /* !!!!!!!!! */
1697 if (cur->childs != NULL) return(cur->childs);
1698 if (cur->next != NULL) return(cur->next);
1699
1700 do {
1701 cur = cur->parent;
1702 if (cur == NULL) return(NULL);
1703 if (cur == ctxt->context->doc->root) return(NULL);
1704 if (cur->next != NULL) {
1705 cur = cur->next;
1706 return(cur);
1707 }
1708 } while (cur != NULL);
1709 return(cur);
1710}
1711
1712/**
1713 * xmlXPathNextPreceding:
1714 * @ctxt: the XPath Parser context
1715 * @cur: the current node in the traversal
1716 *
1717 * Traversal function for the "preceding" direction
1718 * the preceding axis contains all nodes in the same document as the context
1719 * node that are before the context node in document order, excluding any
1720 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1721 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001722 *
1723 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001724 */
1725xmlNodePtr
1726xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001727 if (cur == (xmlNodePtr) ctxt->context->doc)
1728 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001729 if (cur == NULL)
1730 return(ctxt->context->node->prev); /* !!!!!!!!! */
1731 if (cur->last != NULL) return(cur->last);
1732 if (cur->prev != NULL) return(cur->prev);
1733
1734 do {
1735 cur = cur->parent;
1736 if (cur == NULL) return(NULL);
1737 if (cur == ctxt->context->doc->root) return(NULL);
1738 if (cur->prev != NULL) {
1739 cur = cur->prev;
1740 return(cur);
1741 }
1742 } while (cur != NULL);
1743 return(cur);
1744}
1745
1746/**
1747 * xmlXPathNextNamespace:
1748 * @ctxt: the XPath Parser context
1749 * @cur: the current attribute in the traversal
1750 *
1751 * Traversal function for the "namespace" direction
1752 * the namespace axis contains the namespace nodes of the context node;
1753 * the order of nodes on this axis is implementation-defined; the axis will
1754 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001755 *
1756 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001757 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001758xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001759xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001760 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1761 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001762 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001763 ctxt->context->namespaces =
1764 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1765 if (ctxt->context->namespaces == NULL) return(NULL);
1766 ctxt->context->nsNr = 0;
1767 }
1768 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001769}
1770
1771/**
1772 * xmlXPathNextAttribute:
1773 * @ctxt: the XPath Parser context
1774 * @cur: the current attribute in the traversal
1775 *
1776 * Traversal function for the "attribute" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001777 *
1778 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001779 */
1780xmlAttrPtr
1781xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001782 if (cur == NULL) {
1783 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1784 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001785 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001786 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001787 return(cur->next);
1788}
1789
1790/************************************************************************
1791 * *
1792 * NodeTest Functions *
1793 * *
1794 ************************************************************************/
1795
1796#define NODE_TEST_NONE 0
1797#define NODE_TEST_TYPE 1
1798#define NODE_TEST_PI 2
1799#define NODE_TEST_ALL 3
1800#define NODE_TEST_NS 4
1801#define NODE_TEST_NAME 5
1802
1803#define NODE_TYPE_COMMENT 50
1804#define NODE_TYPE_TEXT 51
1805#define NODE_TYPE_PI 52
1806#define NODE_TYPE_NODE 53
1807
1808#define IS_FUNCTION 200
1809
1810/**
1811 * xmlXPathNodeCollectAndTest:
1812 * @ctxt: the XPath Parser context
1813 * @cur: the current node to test
1814 *
1815 * This is the function implementing a step: based on the current list
1816 * of nodes, it builds up a new list, looking at all nodes under that
1817 * axis and selecting them.
1818 *
1819 * Returns the new NodeSet resulting from the search.
1820 */
1821xmlNodeSetPtr
1822xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
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