blob: 3a703bb70ff9f2fe16363cabfeecaa26ae8836ef [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 Veillardb05deb71999-08-10 19:04:08 +0000565 if (obj->nodeTab[i]->type == XML_DOCUMENT_NODE)
566 fprintf(output, " /");
567 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000568 fprintf(output, " noname!");
569 else fprintf(output, " %s", obj->nodeTab[i]->name);
570 }
571 fprintf(output, "\n");
572}
573#endif
574
575/************************************************************************
576 * *
577 * Routines to handle Variable *
578 * *
579 * UNIMPLEMENTED CURRENTLY *
580 * *
581 ************************************************************************/
582
583/**
584 * xmlXPathVariablelookup:
585 * @ctxt: the XPath Parser context
586 * @prefix: the variable name namespace if any
587 * @name: the variable name
588 *
589 * Search in the Variable array of the context for the given
590 * variable value.
591 *
592 * UNIMPLEMENTED: always return NULL.
593 *
594 * Returns the value or NULL if not found
595 */
596xmlXPathObjectPtr
597xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000598 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000599 return(NULL);
600}
601
602/************************************************************************
603 * *
604 * Routines to handle Values *
605 * *
606 ************************************************************************/
607
608/* Allocations are terrible, one need to optimize all this !!! */
609
610/**
611 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000612 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000613 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000614 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000615 *
616 * Returns the newly created object.
617 */
618xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000619xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000620 xmlXPathObjectPtr ret;
621
Daniel Veillard6454aec1999-09-02 22:04:43 +0000622 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000623 if (ret == NULL) {
624 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
625 return(NULL);
626 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000627 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000628 ret->type = XPATH_NUMBER;
629 ret->floatval = val;
630 return(ret);
631}
632
633/**
634 * xmlXPathNewBoolean:
635 * @val: the boolean value
636 *
637 * Create a new xmlXPathObjectPtr of type boolean and of value @val
638 *
639 * Returns the newly created object.
640 */
641xmlXPathObjectPtr
642xmlXPathNewBoolean(int val) {
643 xmlXPathObjectPtr ret;
644
Daniel Veillard6454aec1999-09-02 22:04:43 +0000645 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000646 if (ret == NULL) {
647 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
648 return(NULL);
649 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000650 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000651 ret->type = XPATH_BOOLEAN;
652 ret->boolval = (val != 0);
653 return(ret);
654}
655
656/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000657 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000658 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000659 *
660 * Create a new xmlXPathObjectPtr of type string and of value @val
661 *
662 * Returns the newly created object.
663 */
664xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000665xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000666 xmlXPathObjectPtr ret;
667
Daniel Veillard6454aec1999-09-02 22:04:43 +0000668 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000669 if (ret == NULL) {
670 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
671 return(NULL);
672 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000673 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000674 ret->type = XPATH_STRING;
675 ret->stringval = xmlStrdup(val);
676 return(ret);
677}
678
679/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000680 * xmlXPathNewCString:
681 * @val: the char * value
682 *
683 * Create a new xmlXPathObjectPtr of type string and of value @val
684 *
685 * Returns the newly created object.
686 */
687xmlXPathObjectPtr
688xmlXPathNewCString(const char *val) {
689 xmlXPathObjectPtr ret;
690
Daniel Veillard6454aec1999-09-02 22:04:43 +0000691 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000692 if (ret == NULL) {
693 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
694 return(NULL);
695 }
696 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
697 ret->type = XPATH_STRING;
698 ret->stringval = xmlStrdup(BAD_CAST val);
699 return(ret);
700}
701
702/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000703 * xmlXPathNewNodeSet:
704 * @val: the NodePtr value
705 *
706 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
707 * it with the single Node @val
708 *
709 * Returns the newly created object.
710 */
711xmlXPathObjectPtr
712xmlXPathNewNodeSet(xmlNodePtr val) {
713 xmlXPathObjectPtr ret;
714
Daniel Veillard6454aec1999-09-02 22:04:43 +0000715 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000716 if (ret == NULL) {
717 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
718 return(NULL);
719 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000720 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000721 ret->type = XPATH_NODESET;
722 ret->nodesetval = xmlXPathNodeSetCreate(val);
723 return(ret);
724}
725
726/**
727 * xmlXPathNewNodeSetList:
728 * @val: an existing NodeSet
729 *
730 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
731 * it with the Nodeset @val
732 *
733 * Returns the newly created object.
734 */
735xmlXPathObjectPtr
736xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
737 xmlXPathObjectPtr ret;
738
Daniel Veillard6454aec1999-09-02 22:04:43 +0000739 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000740 if (ret == NULL) {
741 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
742 return(NULL);
743 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000744 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000745 ret->type = XPATH_NODESET;
746 ret->nodesetval = val;
747 return(ret);
748}
749
750/**
751 * xmlXPathFreeObject:
752 * @obj: the object to free
753 *
754 * Free up an xmlXPathObjectPtr object.
755 */
756void
757xmlXPathFreeObject(xmlXPathObjectPtr obj) {
758 if (obj == NULL) return;
759 if (obj->nodesetval != NULL)
760 xmlXPathFreeNodeSet(obj->nodesetval);
761 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000762 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000763#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000764 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000765#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000766 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000767}
768
769/************************************************************************
770 * *
771 * Routines to handle XPath contexts *
772 * *
773 ************************************************************************/
774
775/**
776 * xmlXPathNewContext:
777 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000778 *
779 * Create a new xmlXPathContext
780 *
781 * Returns the xmlXPathContext just allocated.
782 */
783xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000784xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000785 xmlXPathContextPtr ret;
786
Daniel Veillard6454aec1999-09-02 22:04:43 +0000787 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000788 if (ret == NULL) {
789 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
790 return(NULL);
791 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000792 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000793 ret->doc = doc;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000794
795 ret->nb_variables = 0;
796 ret->max_variables = 0;
797 ret->variables = NULL;
798
799 ret->nb_types = 0;
800 ret->max_types = 0;
801 ret->types = NULL;
802
803 ret->nb_funcs = 0;
804 ret->max_funcs = 0;
805 ret->funcs = NULL;
806
807 ret->nb_axis = 0;
808 ret->max_axis = 0;
809 ret->axis = NULL;
810
Daniel Veillardb96e6431999-08-29 21:02:19 +0000811 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000812 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000813 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000814 return(ret);
815}
816
817/**
818 * xmlXPathFreeContext:
819 * @ctxt: the context to free
820 *
821 * Free up an xmlXPathContext
822 */
823void
824xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000825 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000826 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000827
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000828#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000829 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000830#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000831 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000832}
833
834/************************************************************************
835 * *
836 * Routines to handle XPath parser contexts *
837 * *
838 ************************************************************************/
839
840#define CHECK_CTXT \
841 if (ctxt == NULL) { \
842 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
843 __FILE__, __LINE__); \
844 } \
845
846
847#define CHECK_CONTEXT \
848 if (ctxt == NULL) { \
849 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
850 __FILE__, __LINE__); \
851 } \
852 if (ctxt->doc == NULL) { \
853 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
854 __FILE__, __LINE__); \
855 } \
856 if (ctxt->doc->root == NULL) { \
857 fprintf(xmlXPathDebug, \
858 "%s:%d Internal error: document without root\n", \
859 __FILE__, __LINE__); \
860 } \
861
862
863/**
864 * xmlXPathNewParserContext:
865 * @str: the XPath expression
866 * @ctxt: the XPath context
867 *
868 * Create a new xmlXPathParserContext
869 *
870 * Returns the xmlXPathParserContext just allocated.
871 */
872xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000873xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000874 xmlXPathParserContextPtr ret;
875
Daniel Veillard6454aec1999-09-02 22:04:43 +0000876 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000877 if (ret == NULL) {
878 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
879 return(NULL);
880 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000881 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000882 ret->cur = ret->base = str;
883 ret->context = ctxt;
884
885 /* Allocate the value stack */
886 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000887 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000888 ret->valueNr = 0;
889 ret->valueMax = 10;
890 ret->value = NULL;
891 return(ret);
892}
893
894/**
895 * xmlXPathFreeParserContext:
896 * @ctxt: the context to free
897 *
898 * Free up an xmlXPathParserContext
899 */
900void
901xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
902 if (ctxt->valueTab != NULL) {
903#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000904 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000905#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000906 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000907 }
908#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000909 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000910#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000911 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000912}
913
914/************************************************************************
915 * *
916 * The implicit core function library *
917 * *
918 ************************************************************************/
919
920/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000921 * Auto-pop and cast to a number
922 */
923void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
924
925#define CHECK_ARITY(x) \
926 if (nargs != (x)) { \
927 ERROR(XPATH_INVALID_ARITY); \
928 } \
929
930
931#define POP_FLOAT \
932 arg = valuePop(ctxt); \
933 if (arg == NULL) { \
934 ERROR(XPATH_INVALID_OPERAND); \
935 } \
936 if (arg->type != XPATH_NUMBER) { \
937 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000938 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000939 arg = valuePop(ctxt); \
940 }
941
942/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000943 * xmlXPathEqualNodeSetString
944 * @arg: the nodeset object argument
945 * @str: the string to compare to.
946 *
947 * Implement the equal operation on XPath objects content: @arg1 == @arg2
948 * If one object to be compared is a node-set and the other is a string,
949 * then the comparison will be true if and only if there is a node in
950 * the node-set such that the result of performing the comparison on the
951 * string-value of the node and the other string is true.
952 *
953 * Returns 0 or 1 depending on the results of the test.
954 */
955int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000956xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000957 int i;
958 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000959 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000960
961 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
962 return(0);
963 ns = arg->nodesetval;
964 for (i = 0;i < ns->nodeNr;i++) {
965 str2 = xmlNodeGetContent(ns->nodeTab[i]);
966 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000967 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000968 return(1);
969 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000970 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000971 }
972 return(0);
973}
974
975/**
976 * xmlXPathEqualNodeSetFloat
977 * @arg: the nodeset object argument
978 * @f: the float to compare to
979 *
980 * Implement the equal operation on XPath objects content: @arg1 == @arg2
981 * If one object to be compared is a node-set and the other is a number,
982 * then the comparison will be true if and only if there is a node in
983 * the node-set such that the result of performing the comparison on the
984 * number to be compared and on the result of converting the string-value
985 * of that node to a number using the number function is true.
986 *
987 * Returns 0 or 1 depending on the results of the test.
988 */
989int
990xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000991 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +0000992
993 if ((arg == NULL) || (arg->type != XPATH_NODESET))
994 return(0);
995
996 if (isnan(f))
997 sprintf(buf, "NaN");
998 else if (isinf(f) > 0)
999 sprintf(buf, "+Infinity");
1000 else if (isinf(f) < 0)
1001 sprintf(buf, "-Infinity");
1002 else
1003 sprintf(buf, "%0g", f);
1004
Daniel Veillardb96e6431999-08-29 21:02:19 +00001005 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001006}
1007
1008
1009/**
1010 * xmlXPathEqualNodeSets
1011 * @arg1: first nodeset object argument
1012 * @arg2: second nodeset object argument
1013 *
1014 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1015 * If both objects to be compared are node-sets, then the comparison
1016 * will be true if and only if there is a node in the first node-set and
1017 * a node in the second node-set such that the result of performing the
1018 * comparison on the string-values of the two nodes is true.
1019 *
1020 * (needless to say, this is a costly operation)
1021 *
1022 * Returns 0 or 1 depending on the results of the test.
1023 */
1024int
1025xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1026 int i;
1027 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001028 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001029
1030 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1031 return(0);
1032 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1033 return(0);
1034
1035 ns = arg1->nodesetval;
1036 for (i = 0;i < ns->nodeNr;i++) {
1037 str = xmlNodeGetContent(ns->nodeTab[i]);
1038 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001039 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001040 return(1);
1041 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001042 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001043 }
1044 return(0);
1045}
1046
1047/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001048 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001049 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001050 *
1051 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1052 *
1053 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001054 */
1055int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001056xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1057 xmlXPathObjectPtr arg1, arg2;
1058 int ret = 0;
1059
1060 arg1 = valuePop(ctxt);
1061 if (arg1 == NULL)
1062 ERROR0(XPATH_INVALID_OPERAND);
1063
1064 arg2 = valuePop(ctxt);
1065 if (arg2 == NULL) {
1066 xmlXPathFreeObject(arg1);
1067 ERROR0(XPATH_INVALID_OPERAND);
1068 }
1069
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001070 if (arg1 == arg2) {
1071#ifdef DEBUG_EXPR
1072 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1073#endif
1074 return(1);
1075 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001076
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001077 switch (arg1->type) {
1078 case XPATH_UNDEFINED:
1079#ifdef DEBUG_EXPR
1080 fprintf(xmlXPathDebug, "Equal: undefined\n");
1081#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001082 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001083 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001084 switch (arg2->type) {
1085 case XPATH_UNDEFINED:
1086#ifdef DEBUG_EXPR
1087 fprintf(xmlXPathDebug, "Equal: undefined\n");
1088#endif
1089 break;
1090 case XPATH_NODESET:
1091 ret = xmlXPathEqualNodeSets(arg1, arg2);
1092 break;
1093 case XPATH_BOOLEAN:
1094 if ((arg1->nodesetval == NULL) ||
1095 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1096 else
1097 ret = 1;
1098 ret = (ret == arg2->boolval);
1099 break;
1100 case XPATH_NUMBER:
1101 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1102 break;
1103 case XPATH_STRING:
1104 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1105 break;
1106 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001107 break;
1108 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001109 switch (arg2->type) {
1110 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001111#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001112 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001113#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001114 break;
1115 case XPATH_NODESET:
1116 if ((arg2->nodesetval == NULL) ||
1117 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1118 else
1119 ret = 1;
1120 break;
1121 case XPATH_BOOLEAN:
1122#ifdef DEBUG_EXPR
1123 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1124 arg1->boolval, arg2->boolval);
1125#endif
1126 ret = (arg1->boolval == arg2->boolval);
1127 break;
1128 case XPATH_NUMBER:
1129 if (arg2->floatval) ret = 1;
1130 else ret = 0;
1131 ret = (arg1->boolval == ret);
1132 break;
1133 case XPATH_STRING:
1134 if ((arg2->stringval == NULL) ||
1135 (arg2->stringval[0] == 0)) ret = 0;
1136 else
1137 ret = 1;
1138 ret = (arg1->boolval == ret);
1139 break;
1140 }
1141 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001142 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001143 switch (arg2->type) {
1144 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001145#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001146 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001147#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001148 break;
1149 case XPATH_NODESET:
1150 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1151 break;
1152 case XPATH_BOOLEAN:
1153 if (arg1->floatval) ret = 1;
1154 else ret = 0;
1155 ret = (arg2->boolval == ret);
1156 break;
1157 case XPATH_STRING:
1158 valuePush(ctxt, arg2);
1159 xmlXPathNumberFunction(ctxt, 1);
1160 arg2 = valuePop(ctxt);
1161 /* no break on purpose */
1162 case XPATH_NUMBER:
1163 ret = (arg1->floatval == arg2->floatval);
1164 break;
1165 }
1166 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001167 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001168 switch (arg2->type) {
1169 case XPATH_UNDEFINED:
1170#ifdef DEBUG_EXPR
1171 fprintf(xmlXPathDebug, "Equal: undefined\n");
1172#endif
1173 break;
1174 case XPATH_NODESET:
1175 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1176 break;
1177 case XPATH_BOOLEAN:
1178 if ((arg1->stringval == NULL) ||
1179 (arg1->stringval[0] == 0)) ret = 0;
1180 else
1181 ret = 1;
1182 ret = (arg2->boolval == ret);
1183 break;
1184 case XPATH_STRING:
1185 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1186 break;
1187 case XPATH_NUMBER:
1188 valuePush(ctxt, arg1);
1189 xmlXPathNumberFunction(ctxt, 1);
1190 arg1 = valuePop(ctxt);
1191 ret = (arg1->floatval == arg2->floatval);
1192 break;
1193 }
1194 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001195#ifdef DEBUG_EXPR
1196 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
1197 arg1->stringval, arg2->stringval);
1198#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001199 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001200 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001201 xmlXPathFreeObject(arg1);
1202 xmlXPathFreeObject(arg2);
1203 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001204}
1205
1206/**
1207 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001208 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001209 * @inf: less than (1) or greater than (2)
1210 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001211 *
1212 * Implement the compare operation on XPath objects:
1213 * @arg1 < @arg2 (1, 1, ...
1214 * @arg1 <= @arg2 (1, 0, ...
1215 * @arg1 > @arg2 (0, 1, ...
1216 * @arg1 >= @arg2 (0, 0, ...
1217 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001218 * When neither object to be compared is a node-set and the operator is
1219 * <=, <, >=, >, then the objects are compared by converted both objects
1220 * to numbers and comparing the numbers according to IEEE 754. The <
1221 * comparison will be true if and only if the first number is less than the
1222 * second number. The <= comparison will be true if and only if the first
1223 * number is less than or equal to the second number. The > comparison
1224 * will be true if and only if the first number is greater than the second
1225 * number. The >= comparison will be true if and only if the first number
1226 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001227 */
1228int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001229xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1230 int ret = 0;
1231 xmlXPathObjectPtr arg1, arg2;
1232
1233 arg2 = valuePop(ctxt);
1234 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1235 if (arg2 != NULL)
1236 xmlXPathFreeObject(arg2);
1237 ERROR0(XPATH_INVALID_OPERAND);
1238 }
1239
1240 arg1 = valuePop(ctxt);
1241 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1242 if (arg1 != NULL)
1243 xmlXPathFreeObject(arg1);
1244 xmlXPathFreeObject(arg2);
1245 ERROR0(XPATH_INVALID_OPERAND);
1246 }
1247
1248 if (arg1->type != XPATH_NUMBER) {
1249 valuePush(ctxt, arg1);
1250 xmlXPathNumberFunction(ctxt, 1);
1251 arg1 = valuePop(ctxt);
1252 }
1253 if (arg1->type != XPATH_NUMBER) {
1254 xmlXPathFreeObject(arg1);
1255 xmlXPathFreeObject(arg2);
1256 ERROR0(XPATH_INVALID_OPERAND);
1257 }
1258 if (arg2->type != XPATH_NUMBER) {
1259 valuePush(ctxt, arg2);
1260 xmlXPathNumberFunction(ctxt, 1);
1261 arg2 = valuePop(ctxt);
1262 }
1263 if (arg2->type != XPATH_NUMBER) {
1264 xmlXPathFreeObject(arg1);
1265 xmlXPathFreeObject(arg2);
1266 ERROR0(XPATH_INVALID_OPERAND);
1267 }
1268 /*
1269 * Add tests for infinity and nan
1270 * => feedback on 3.4 for Inf and NaN
1271 */
1272 if (inf && strict)
1273 ret = (arg1->floatval < arg2->floatval);
1274 else if (inf && !strict)
1275 ret = (arg1->floatval <= arg2->floatval);
1276 else if (!inf && strict)
1277 ret = (arg1->floatval > arg2->floatval);
1278 else if (!inf && !strict)
1279 ret = (arg1->floatval >= arg2->floatval);
1280 xmlXPathFreeObject(arg1);
1281 xmlXPathFreeObject(arg2);
1282 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001283}
1284
1285/**
1286 * xmlXPathValueFlipSign:
1287 * @ctxt: the XPath Parser context
1288 *
1289 * Implement the unary - operation on an XPath object
1290 * The numeric operators convert their operands to numbers as if
1291 * by calling the number function.
1292 */
1293void
1294xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1295 xmlXPathObjectPtr arg;
1296
1297 POP_FLOAT
1298 arg->floatval = -arg->floatval;
1299 valuePush(ctxt, arg);
1300}
1301
1302/**
1303 * xmlXPathAddValues:
1304 * @ctxt: the XPath Parser context
1305 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001306 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001307 * The numeric operators convert their operands to numbers as if
1308 * by calling the number function.
1309 */
1310void
1311xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1312 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001313 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001314
1315 POP_FLOAT
1316 val = arg->floatval;
1317 xmlXPathFreeObject(arg);
1318
1319 POP_FLOAT
1320 arg->floatval += val;
1321 valuePush(ctxt, arg);
1322}
1323
1324/**
1325 * xmlXPathSubValues:
1326 * @ctxt: the XPath Parser context
1327 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001328 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001329 * The numeric operators convert their operands to numbers as if
1330 * by calling the number function.
1331 */
1332void
1333xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1334 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001335 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001336
1337 POP_FLOAT
1338 val = arg->floatval;
1339 xmlXPathFreeObject(arg);
1340
1341 POP_FLOAT
1342 arg->floatval -= val;
1343 valuePush(ctxt, arg);
1344}
1345
1346/**
1347 * xmlXPathMultValues:
1348 * @ctxt: the XPath Parser context
1349 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001350 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001351 * The numeric operators convert their operands to numbers as if
1352 * by calling the number function.
1353 */
1354void
1355xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1356 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001357 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001358
1359 POP_FLOAT
1360 val = arg->floatval;
1361 xmlXPathFreeObject(arg);
1362
1363 POP_FLOAT
1364 arg->floatval *= val;
1365 valuePush(ctxt, arg);
1366}
1367
1368/**
1369 * xmlXPathDivValues:
1370 * @ctxt: the XPath Parser context
1371 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001372 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001373 * The numeric operators convert their operands to numbers as if
1374 * by calling the number function.
1375 */
1376void
1377xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1378 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001379 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001380
1381 POP_FLOAT
1382 val = arg->floatval;
1383 xmlXPathFreeObject(arg);
1384
1385 POP_FLOAT
1386 arg->floatval /= val;
1387 valuePush(ctxt, arg);
1388}
1389
1390/**
1391 * xmlXPathModValues:
1392 * @ctxt: the XPath Parser context
1393 *
1394 * Implement the div operation on XPath objects: @arg1 / @arg2
1395 * The numeric operators convert their operands to numbers as if
1396 * by calling the number function.
1397 */
1398void
1399xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1400 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001401 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001402
1403 POP_FLOAT
1404 val = arg->floatval;
1405 xmlXPathFreeObject(arg);
1406
1407 POP_FLOAT
1408 arg->floatval /= val;
1409 valuePush(ctxt, arg);
1410}
1411
1412/************************************************************************
1413 * *
1414 * The traversal functions *
1415 * *
1416 ************************************************************************/
1417
1418#define AXIS_ANCESTOR 1
1419#define AXIS_ANCESTOR_OR_SELF 2
1420#define AXIS_ATTRIBUTE 3
1421#define AXIS_CHILD 4
1422#define AXIS_DESCENDANT 5
1423#define AXIS_DESCENDANT_OR_SELF 6
1424#define AXIS_FOLLOWING 7
1425#define AXIS_FOLLOWING_SIBLING 8
1426#define AXIS_NAMESPACE 9
1427#define AXIS_PARENT 10
1428#define AXIS_PRECEDING 11
1429#define AXIS_PRECEDING_SIBLING 12
1430#define AXIS_SELF 13
1431
1432/*
1433 * A traversal function enumerates nodes along an axis.
1434 * Initially it must be called with NULL, and it indicates
1435 * termination on the axis by returning NULL.
1436 */
1437typedef xmlNodePtr (*xmlXPathTraversalFunction)
1438 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1439
1440/**
1441 * mlXPathNextSelf:
1442 * @ctxt: the XPath Parser context
1443 * @cur: the current node in the traversal
1444 *
1445 * Traversal function for the "self" direction
1446 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001447 *
1448 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001449 */
1450xmlNodePtr
1451xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1452 if (cur == NULL)
1453 return(ctxt->context->node);
1454 return(NULL);
1455}
1456
1457/**
1458 * mlXPathNextChild:
1459 * @ctxt: the XPath Parser context
1460 * @cur: the current node in the traversal
1461 *
1462 * Traversal function for the "child" direction
1463 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001464 *
1465 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001466 */
1467xmlNodePtr
1468xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001469 if (cur == NULL) {
1470 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1471 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001472 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001473 }
1474 if (ctxt->context->node->type == XML_DOCUMENT_NODE)
1475 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001476 return(cur->next);
1477}
1478
1479/**
1480 * mlXPathNextDescendant:
1481 * @ctxt: the XPath Parser context
1482 * @cur: the current node in the traversal
1483 *
1484 * Traversal function for the "descendant" direction
1485 * the descendant axis contains the descendants of the context node in document
1486 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001487 *
1488 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001489 */
1490xmlNodePtr
1491xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001492 if (cur == NULL) {
1493 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1494 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001495 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001496 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001497
1498 if (cur->childs != NULL) return(cur->childs);
1499 if (cur->next != NULL) return(cur->next);
1500
1501 do {
1502 cur = cur->parent;
1503 if (cur == NULL) return(NULL);
1504 if (cur == ctxt->context->node) return(NULL);
1505 if (cur->next != NULL) {
1506 cur = cur->next;
1507 return(cur);
1508 }
1509 } while (cur != NULL);
1510 return(cur);
1511}
1512
1513/**
1514 * mlXPathNextDescendantOrSelf:
1515 * @ctxt: the XPath Parser context
1516 * @cur: the current node in the traversal
1517 *
1518 * Traversal function for the "descendant-or-self" direction
1519 * the descendant-or-self axis contains the context node and the descendants
1520 * of the context node in document order; thus the context node is the first
1521 * node on the axis, and the first child of the context node is the second node
1522 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001523 *
1524 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001525 */
1526xmlNodePtr
1527xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1528 if (cur == NULL)
1529 return(ctxt->context->node);
1530
Daniel Veillardb05deb71999-08-10 19:04:08 +00001531 if (cur == (xmlNodePtr) ctxt->context->doc)
1532 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001533 if (cur->childs != NULL) return(cur->childs);
1534 if (cur->next != NULL) return(cur->next);
1535
1536 do {
1537 cur = cur->parent;
1538 if (cur == NULL) return(NULL);
1539 if (cur == ctxt->context->node) return(NULL);
1540 if (cur->next != NULL) {
1541 cur = cur->next;
1542 return(cur);
1543 }
1544 } while (cur != NULL);
1545 return(cur);
1546}
1547
1548/**
1549 * xmlXPathNextParent:
1550 * @ctxt: the XPath Parser context
1551 * @cur: the current node in the traversal
1552 *
1553 * Traversal function for the "parent" direction
1554 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001555 *
1556 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001557 */
1558xmlNodePtr
1559xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1560 /*
1561 * !!!!!!!!!!!!!
1562 * the parent of an attribute or namespace node is the element
1563 * to which the attribute or namespace node is attached
1564 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001565 if (cur == NULL) {
1566 if (ctxt->context->node->parent == NULL)
1567 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001568 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001569 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001570 return(NULL);
1571}
1572
1573/**
1574 * xmlXPathNextAncestor:
1575 * @ctxt: the XPath Parser context
1576 * @cur: the current node in the traversal
1577 *
1578 * Traversal function for the "ancestor" direction
1579 * the ancestor axis contains the ancestors of the context node; the ancestors
1580 * of the context node consist of the parent of context node and the parent's
1581 * parent and so on; the nodes are ordered in reverse document order; thus the
1582 * parent is the first node on the axis, and the parent's parent is the second
1583 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001584 *
1585 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001586 */
1587xmlNodePtr
1588xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1589 /*
1590 * !!!!!!!!!!!!!
1591 * the parent of an attribute or namespace node is the element
1592 * to which the attribute or namespace node is attached
1593 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001594 if (cur == NULL) {
1595 if (ctxt->context->node->parent == NULL)
1596 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001597 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001598 }
1599 if (cur == ctxt->context->doc->root)
1600 return((xmlNodePtr) ctxt->context->doc);
1601 if (cur == (xmlNodePtr) ctxt->context->doc)
1602 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001603 return(cur->parent);
1604}
1605
1606/**
1607 * xmlXPathNextAncestorOrSelf:
1608 * @ctxt: the XPath Parser context
1609 * @cur: the current node in the traversal
1610 *
1611 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001612 * he ancestor-or-self axis contains the context node and ancestors of
1613 * the context node in reverse document order; thus the context node is
1614 * the first node on the axis, and the context node's parent the second;
1615 * parent here is defined the same as with the parent axis.
1616 *
1617 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001618 */
1619xmlNodePtr
1620xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1621 /*
1622 * !!!!!!!!!!!!!
1623 * the parent of an attribute or namespace node is the element
1624 * to which the attribute or namespace node is attached
1625 */
1626 if (cur == NULL)
1627 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001628 if (cur == ctxt->context->doc->root)
1629 return((xmlNodePtr) ctxt->context->doc);
1630 if (cur == (xmlNodePtr) ctxt->context->doc)
1631 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001632 return(cur->parent);
1633}
1634
1635/**
1636 * xmlXPathNextFollowingSibling:
1637 * @ctxt: the XPath Parser context
1638 * @cur: the current node in the traversal
1639 *
1640 * Traversal function for the "following-sibling" direction
1641 * The following-sibling axis contains the following siblings of the context
1642 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001643 *
1644 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001645 */
1646xmlNodePtr
1647xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001648 if (cur == (xmlNodePtr) ctxt->context->doc)
1649 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001650 if (cur == NULL)
1651 return(ctxt->context->node->next);
1652 return(cur->next);
1653}
1654
1655/**
1656 * xmlXPathNextPrecedingSibling:
1657 * @ctxt: the XPath Parser context
1658 * @cur: the current node in the traversal
1659 *
1660 * Traversal function for the "preceding-sibling" direction
1661 * The preceding-sibling axis contains the preceding siblings of the context
1662 * node in reverse document order; the first preceding sibling is first on the
1663 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001664 *
1665 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001666 */
1667xmlNodePtr
1668xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001669 if (cur == (xmlNodePtr) ctxt->context->doc)
1670 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001671 if (cur == NULL)
1672 return(ctxt->context->node->prev);
1673 return(cur->prev);
1674}
1675
1676/**
1677 * xmlXPathNextFollowing:
1678 * @ctxt: the XPath Parser context
1679 * @cur: the current node in the traversal
1680 *
1681 * Traversal function for the "following" direction
1682 * The following axis contains all nodes in the same document as the context
1683 * node that are after the context node in document order, excluding any
1684 * descendants and excluding attribute nodes and namespace nodes; the nodes
1685 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001686 *
1687 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001688 */
1689xmlNodePtr
1690xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001691 if (cur == (xmlNodePtr) ctxt->context->doc)
1692 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001693 if (cur == NULL)
1694 return(ctxt->context->node->next);; /* !!!!!!!!! */
1695 if (cur->childs != NULL) return(cur->childs);
1696 if (cur->next != NULL) return(cur->next);
1697
1698 do {
1699 cur = cur->parent;
1700 if (cur == NULL) return(NULL);
1701 if (cur == ctxt->context->doc->root) return(NULL);
1702 if (cur->next != NULL) {
1703 cur = cur->next;
1704 return(cur);
1705 }
1706 } while (cur != NULL);
1707 return(cur);
1708}
1709
1710/**
1711 * xmlXPathNextPreceding:
1712 * @ctxt: the XPath Parser context
1713 * @cur: the current node in the traversal
1714 *
1715 * Traversal function for the "preceding" direction
1716 * the preceding axis contains all nodes in the same document as the context
1717 * node that are before the context node in document order, excluding any
1718 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1719 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001720 *
1721 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001722 */
1723xmlNodePtr
1724xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001725 if (cur == (xmlNodePtr) ctxt->context->doc)
1726 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001727 if (cur == NULL)
1728 return(ctxt->context->node->prev); /* !!!!!!!!! */
1729 if (cur->last != NULL) return(cur->last);
1730 if (cur->prev != NULL) return(cur->prev);
1731
1732 do {
1733 cur = cur->parent;
1734 if (cur == NULL) return(NULL);
1735 if (cur == ctxt->context->doc->root) return(NULL);
1736 if (cur->prev != NULL) {
1737 cur = cur->prev;
1738 return(cur);
1739 }
1740 } while (cur != NULL);
1741 return(cur);
1742}
1743
1744/**
1745 * xmlXPathNextNamespace:
1746 * @ctxt: the XPath Parser context
1747 * @cur: the current attribute in the traversal
1748 *
1749 * Traversal function for the "namespace" direction
1750 * the namespace axis contains the namespace nodes of the context node;
1751 * the order of nodes on this axis is implementation-defined; the axis will
1752 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001753 *
1754 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001755 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001756xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001757xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001758 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1759 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001760 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001761 ctxt->context->namespaces =
1762 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1763 if (ctxt->context->namespaces == NULL) return(NULL);
1764 ctxt->context->nsNr = 0;
1765 }
1766 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001767}
1768
1769/**
1770 * xmlXPathNextAttribute:
1771 * @ctxt: the XPath Parser context
1772 * @cur: the current attribute in the traversal
1773 *
1774 * Traversal function for the "attribute" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001775 *
1776 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001777 */
1778xmlAttrPtr
1779xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001780 if (cur == NULL) {
1781 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1782 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001783 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001784 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001785 return(cur->next);
1786}
1787
1788/************************************************************************
1789 * *
1790 * NodeTest Functions *
1791 * *
1792 ************************************************************************/
1793
1794#define NODE_TEST_NONE 0
1795#define NODE_TEST_TYPE 1
1796#define NODE_TEST_PI 2
1797#define NODE_TEST_ALL 3
1798#define NODE_TEST_NS 4
1799#define NODE_TEST_NAME 5
1800
1801#define NODE_TYPE_COMMENT 50
1802#define NODE_TYPE_TEXT 51
1803#define NODE_TYPE_PI 52
1804#define NODE_TYPE_NODE 53
1805
1806#define IS_FUNCTION 200
1807
1808/**
1809 * xmlXPathNodeCollectAndTest:
1810 * @ctxt: the XPath Parser context
1811 * @cur: the current node to test
1812 *
1813 * This is the function implementing a step: based on the current list
1814 * of nodes, it builds up a new list, looking at all nodes under that
1815 * axis and selecting them.
1816 *
1817 * Returns the new NodeSet resulting from the search.
1818 */
1819xmlNodeSetPtr
1820xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001821 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001822#ifdef DEBUG_STEP
1823 int n = 0, t = 0;
1824#endif
1825 int i;
1826 xmlNodeSetPtr ret;
1827 xmlXPathTraversalFunction next = NULL;
1828 xmlNodePtr cur = NULL;
1829
1830 if (ctxt->context->nodelist == NULL) {
1831 if (ctxt->context->node == NULL) {
1832 fprintf(xmlXPathDebug,
1833 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1834 __FILE__, __LINE__);
1835 return(NULL);
1836 }
1837 STRANGE
1838 return(NULL);
1839 }
1840#ifdef DEBUG_STEP
1841 fprintf(xmlXPathDebug, "new step : ");
1842#endif
1843 switch (axis) {
1844 case AXIS_ANCESTOR:
1845#ifdef DEBUG_STEP
1846 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1847#endif
1848 next = xmlXPathNextAncestor; break;
1849 case AXIS_ANCESTOR_OR_SELF:
1850#ifdef DEBUG_STEP
1851 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1852#endif
1853 next = xmlXPathNextAncestorOrSelf; break;
1854 case AXIS_ATTRIBUTE:
1855#ifdef DEBUG_STEP
1856 fprintf(xmlXPathDebug, "axis 'attributes' ");
1857#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001858 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001859 break;
1860 case AXIS_CHILD:
1861#ifdef DEBUG_STEP
1862 fprintf(xmlXPathDebug, "axis 'child' ");
1863#endif
1864 next = xmlXPathNextChild; break;
1865 case AXIS_DESCENDANT:
1866#ifdef DEBUG_STEP
1867 fprintf(xmlXPathDebug, "axis 'descendant' ");
1868#endif
1869 next = xmlXPathNextDescendant; break;
1870 case AXIS_DESCENDANT_OR_SELF:
1871#ifdef DEBUG_STEP
1872 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1873#endif
1874 next = xmlXPathNextDescendantOrSelf; break;
1875 case AXIS_FOLLOWING:
1876#ifdef DEBUG_STEP
1877 fprintf(xmlXPathDebug, "axis 'following' ");
1878#endif
1879 next = xmlXPathNextFollowing; break;
1880 case AXIS_FOLLOWING_SIBLING:
1881#ifdef DEBUG_STEP
1882 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1883#endif
1884 next = xmlXPathNextFollowingSibling; break;
1885 case AXIS_NAMESPACE:
1886#ifdef DEBUG_STEP
1887 fprintf(xmlXPathDebug, "axis 'namespace' ");
1888#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001889 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001890 break;
1891 case AXIS_PARENT:
1892#ifdef DEBUG_STEP
1893 fprintf(xmlXPathDebug, "axis 'parent' ");
1894#endif
1895 next = xmlXPathNextParent; break;
1896 case AXIS_PRECEDING:
1897#ifdef DEBUG_STEP
1898 fprintf(xmlXPathDebug, "axis 'preceding' ");
1899#endif
1900 next = xmlXPathNextPreceding; break;
1901 case AXIS_PRECEDING_SIBLING:
1902#ifdef DEBUG_STEP
1903 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1904#endif
1905 next = xmlXPathNextPrecedingSibling; break;
1906 case AXIS_SELF:
1907#ifdef DEBUG_STEP
1908 fprintf(xmlXPathDebug, "axis 'self' ");
1909#endif
1910 next = xmlXPathNextSelf; break;
1911 }
1912 if (next == NULL) return(NULL);
1913 ret = xmlXPathNodeSetCreate(NULL);
1914#ifdef DEBUG_STEP
1915 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1916 ctxt->context->nodelist->nodeNr);
1917 switch (test) {
1918 case NODE_TEST_NONE:
1919 fprintf(xmlXPathDebug, " seaching for none !!!\n");
1920 break;
1921 case NODE_TEST_TYPE:
1922 fprintf(xmlXPathDebug, " seaching for type %d\n", type);
1923 break;
1924 case NODE_TEST_PI:
1925 fprintf(xmlXPathDebug, " seaching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001926 break;
1927 case NODE_TEST_ALL:
1928 fprintf(xmlXPathDebug, " seaching for *\n");
1929 break;
1930 case NODE_TEST_NS:
1931 fprintf(xmlXPathDebug, " seaching for namespace %s\n",
1932 prefix);
1933 break;
1934 case NODE_TEST_NAME:
1935 fprintf(xmlXPathDebug, " seaching for name %s\n", name);
1936 if (prefix != NULL)
1937 fprintf(xmlXPathDebug, " with namespace %s\n",
1938 prefix);
1939 break;
1940 }
1941 fprintf(xmlXPathDebug, "Testing : ");
1942#endif
1943 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1944 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1945
1946 cur = NULL;
1947 do {
1948 cur = next(ctxt, cur);
1949 if (cur == NULL) break;
1950#ifdef DEBUG_STEP
1951 t++;
1952 fprintf(xmlXPathDebug, " %s", cur->name);
1953#endif
1954 switch (test) {
1955 case NODE_TEST_NONE:
1956 STRANGE
1957 return(NULL);
1958 case NODE_TEST_TYPE:
1959 if (cur->type == type) {
1960#ifdef DEBUG_STEP
1961 n++;
1962#endif
1963 xmlXPathNodeSetAdd(ret, cur);
1964 }
1965 break;
1966 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001967 if (cur->type == XML_PI_NODE) {
1968 if ((name != NULL) &&
1969 (xmlStrcmp(name, cur->name)))
1970 break;
1971#ifdef DEBUG_STEP
1972 n++;
1973#endif
1974 xmlXPathNodeSetAdd(ret, cur);
1975 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001976 break;
1977 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001978 if ((cur->type == XML_ELEMENT_NODE) ||
1979 (cur->type == XML_ATTRIBUTE_NODE)) {
1980 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001981#ifdef DEBUG_STEP
1982 n++;
1983#endif
1984 xmlXPathNodeSetAdd(ret, cur);
1985 }
1986 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001987 case NODE_TEST_NS: {
1988 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001989 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001990 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001991 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001992 switch (cur->type) {
1993 case XML_ELEMENT_NODE:
1994 if (!xmlStrcmp(name, cur->name) &&
1995 (((prefix == NULL) ||
1996 ((cur->ns != NULL) &&
1997 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001998#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00001999 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002000#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002001 xmlXPathNodeSetAdd(ret, cur);
2002 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002003 break;
2004 case XML_ATTRIBUTE_NODE: {
2005 xmlAttrPtr attr = (xmlAttrPtr) cur;
2006 if (!xmlStrcmp(name, attr->name)) {
2007#ifdef DEBUG_STEP
2008 n++;
2009#endif
2010 xmlXPathNodeSetAdd(ret, cur);
2011 }
2012 break;
2013 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002014 default:
2015 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002016 }
2017 break;
2018
2019 }
2020 } while (cur != NULL);
2021 }
2022#ifdef DEBUG_STEP
2023 fprintf(xmlXPathDebug,
2024 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2025#endif
2026 return(ret);
2027}
2028
2029
2030/************************************************************************
2031 * *
2032 * Implicit tree core function library *
2033 * *
2034 ************************************************************************/
2035
2036/**
2037 * xmlXPathRoot:
2038 * @ctxt: the XPath Parser context
2039 *
2040 * Initialize the context to the root of the document
2041 */
2042void
2043xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2044 if (ctxt->context->nodelist != NULL)
2045 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002046 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2047 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002048}
2049
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002050/************************************************************************
2051 * *
2052 * The explicit core function library *
2053 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2054 * *
2055 ************************************************************************/
2056
2057
2058/**
2059 * xmlXPathLastFunction:
2060 * @ctxt: the XPath Parser context
2061 *
2062 * Implement the last() XPath function
2063 * The last function returns the number of nodes in the context node list.
2064 */
2065void
2066xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2067 CHECK_ARITY(0);
2068 if ((ctxt->context->nodelist == NULL) ||
2069 (ctxt->context->node == NULL) ||
2070 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002071 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002072 } else {
2073 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002074 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002075 }
2076}
2077
2078/**
2079 * xmlXPathPositionFunction:
2080 * @ctxt: the XPath Parser context
2081 *
2082 * Implement the position() XPath function
2083 * The position function returns the position of the context node in the
2084 * context node list. The first position is 1, and so the last positionr
2085 * will be equal to last().
2086 */
2087void
2088xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2089 int i;
2090
2091 CHECK_ARITY(0);
2092 if ((ctxt->context->nodelist == NULL) ||
2093 (ctxt->context->node == NULL) ||
2094 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002095 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002096 }
2097 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2098 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002099 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002100 return;
2101 }
2102 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002103 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002104}
2105
2106/**
2107 * xmlXPathCountFunction:
2108 * @ctxt: the XPath Parser context
2109 *
2110 * Implement the count() XPath function
2111 */
2112void
2113xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2114 xmlXPathObjectPtr cur;
2115
2116 CHECK_ARITY(1);
2117 CHECK_TYPE(XPATH_NODESET);
2118 cur = valuePop(ctxt);
2119
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002120 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002121 xmlXPathFreeObject(cur);
2122}
2123
2124/**
2125 * xmlXPathIdFunction:
2126 * @ctxt: the XPath Parser context
2127 *
2128 * Implement the id() XPath function
2129 * The id function selects elements by their unique ID
2130 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2131 * then the result is the union of the result of applying id to the
2132 * string value of each of the nodes in the argument node-set. When the
2133 * argument to id is of any other type, the argument is converted to a
2134 * string as if by a call to the string function; the string is split
2135 * into a whitespace-separated list of tokens (whitespace is any sequence
2136 * of characters matching the production S); the result is a node-set
2137 * containing the elements in the same document as the context node that
2138 * have a unique ID equal to any of the tokens in the list.
2139 */
2140void
2141xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002142 const xmlChar *tokens;
2143 const xmlChar *cur;
2144 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002145 xmlAttrPtr attr;
2146 xmlNodePtr elem = NULL;
2147 xmlXPathObjectPtr ret, obj;
2148
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002149 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002150 obj = valuePop(ctxt);
2151 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2152 if (obj->type == XPATH_NODESET) {
2153 TODO /* ID function in case of NodeSet */
2154 }
2155 if (obj->type != XPATH_STRING) {
2156 valuePush(ctxt, obj);
2157 xmlXPathStringFunction(ctxt, 1);
2158 obj = valuePop(ctxt);
2159 if (obj->type != XPATH_STRING) {
2160 xmlXPathFreeObject(obj);
2161 return;
2162 }
2163 }
2164 tokens = obj->stringval;
2165
2166 ret = xmlXPathNewNodeSet(NULL);
2167 valuePush(ctxt, ret);
2168 if (tokens == NULL) {
2169 xmlXPathFreeObject(obj);
2170 return;
2171 }
2172
2173 cur = tokens;
2174
2175 while (IS_BLANK(*cur)) cur++;
2176 while (*cur != 0) {
2177 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2178 (*cur == '.') || (*cur == '-') ||
2179 (*cur == '_') || (*cur == ':') ||
2180 (IS_COMBINING(*cur)) ||
2181 (IS_EXTENDER(*cur)))
2182 cur++;
2183
2184 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2185
2186 ID = xmlStrndup(tokens, cur - tokens);
2187 attr = xmlGetID(ctxt->context->doc, ID);
2188 if (attr != NULL) {
2189 elem = attr->node;
2190 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2191 }
2192 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002193 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002194
2195 while (IS_BLANK(*cur)) cur++;
2196 tokens = cur;
2197 }
2198 xmlXPathFreeObject(obj);
2199 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002200}
2201
2202/**
2203 * xmlXPathLocalPartFunction:
2204 * @ctxt: the XPath Parser context
2205 *
2206 * Implement the local-part() XPath function
2207 * The local-part function returns a string containing the local part
2208 * of the name of the node in the argument node-set that is first in
2209 * document order. If the node-set is empty or the first node has no
2210 * name, an empty string is returned. If the argument is omitted it
2211 * defaults to the context node.
2212 */
2213void
2214xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2215 xmlXPathObjectPtr cur;
2216
2217 CHECK_ARITY(1);
2218 CHECK_TYPE(XPATH_NODESET);
2219 cur = valuePop(ctxt);
2220
2221 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002222 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002223 } else {
2224 int i = 0; /* Should be first in document order !!!!! */
2225 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2226 }
2227 xmlXPathFreeObject(cur);
2228}
2229
2230/**
2231 * xmlXPathNamespaceFunction:
2232 * @ctxt: the XPath Parser context
2233 *
2234 * Implement the namespace() XPath function
2235 * The namespace function returns a string containing the namespace URI
2236 * of the expanded name of the node in the argument node-set that is
2237 * first in document order. If the node-set is empty, the first node has
2238 * no name, or the expanded name has no namespace URI, an empty string
2239 * is returned. If the argument is omitted it defaults to the context node.
2240 */
2241void
2242xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2243 xmlXPathObjectPtr cur;
2244
Daniel Veillardb96e6431999-08-29 21:02:19 +00002245 if (nargs == 0) {
2246 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2247 nargs = 1;
2248 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002249 CHECK_ARITY(1);
2250 CHECK_TYPE(XPATH_NODESET);
2251 cur = valuePop(ctxt);
2252
2253 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002254 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002255 } else {
2256 int i = 0; /* Should be first in document order !!!!! */
2257
2258 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002259 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002260 else
2261 valuePush(ctxt, xmlXPathNewString(
2262 cur->nodesetval->nodeTab[i]->ns->href));
2263 }
2264 xmlXPathFreeObject(cur);
2265}
2266
2267/**
2268 * xmlXPathNameFunction:
2269 * @ctxt: the XPath Parser context
2270 *
2271 * Implement the name() XPath function
2272 * The name function returns a string containing a QName representing
2273 * the name of the node in the argument node-set that is first in documenti
2274 * order. The QName must represent the name with respect to the namespace
2275 * declarations in effect on the node whose name is being represented.
2276 * Typically, this will be the form in which the name occurred in the XML
2277 * source. This need not be the case if there are namespace declarations
2278 * in effect on the node that associate multiple prefixes with the same
2279 * namespace. However, an implementation may include information about
2280 * the original prefix in its representation of nodes; in this case, an
2281 * implementation can ensure that the returned string is always the same
2282 * as the QName used in the XML source. If the argument it omitted it
2283 * defaults to the context node.
2284 * Libxml keep the original prefix so the "real qualified name" used is
2285 * returned.
2286 */
2287void
2288xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2289 xmlXPathObjectPtr cur;
2290
2291 CHECK_ARITY(1);
2292 CHECK_TYPE(XPATH_NODESET);
2293 cur = valuePop(ctxt);
2294
2295 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002296 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002297 } else {
2298 int i = 0; /* Should be first in document order !!!!! */
2299
2300 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2301 valuePush(ctxt, xmlXPathNewString(
2302 cur->nodesetval->nodeTab[i]->name));
2303
2304 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002305 char name[2000];
2306 sprintf(name, "%s:%s",
2307 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2308 (char *) cur->nodesetval->nodeTab[i]->name);
2309 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002310 }
2311 }
2312 xmlXPathFreeObject(cur);
2313}
2314
2315/**
2316 * xmlXPathStringFunction:
2317 * @ctxt: the XPath Parser context
2318 *
2319 * Implement the string() XPath function
2320 * he string function converts an object to a string as follows:
2321 * - A node-set is converted to a string by returning the value of
2322 * the node in the node-set that is first in document order.
2323 * If the node-set is empty, an empty string is returned.
2324 * - A number is converted to a string as follows
2325 * + NaN is converted to the string NaN
2326 * + positive zero is converted to the string 0
2327 * + negative zero is converted to the string 0
2328 * + positive infinity is converted to the string Infinity
2329 * + negative infinity is converted to the string -Infinity
2330 * + if the number is an integer, the number is represented in
2331 * decimal form as a Number with no decimal point and no leading
2332 * zeros, preceded by a minus sign (-) if the number is negative
2333 * + otherwise, the number is represented in decimal form as a
2334 * Number including a decimal point with at least one digit
2335 * before the decimal point and at least one digit after the
2336 * decimal point, preceded by a minus sign (-) if the number
2337 * is negative; there must be no leading zeros before the decimal
2338 * point apart possibly from the one required digit immediatelyi
2339 * before the decimal point; beyond the one required digit
2340 * after the decimal point there must be as many, but only as
2341 * many, more digits as are needed to uniquely distinguish the
2342 * number from all other IEEE 754 numeric values.
2343 * - The boolean false value is converted to the string false.
2344 * The boolean true value is converted to the string true.
2345 */
2346void
2347xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2348 xmlXPathObjectPtr cur;
2349
2350 CHECK_ARITY(1);
2351 cur = valuePop(ctxt);
2352 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2353 switch (cur->type) {
2354 case XPATH_NODESET:
2355 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002356 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002357 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002358 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002359 int i = 0; /* Should be first in document order !!!!! */
2360 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2361 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002362 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002363 }
2364 xmlXPathFreeObject(cur);
2365 return;
2366 case XPATH_STRING:
2367 valuePush(ctxt, cur);
2368 return;
2369 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002370 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2371 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002372 xmlXPathFreeObject(cur);
2373 return;
2374 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002375 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002376
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002377 if (isnan(cur->floatval))
2378 sprintf(buf, "NaN");
2379 else if (isinf(cur->floatval) > 0)
2380 sprintf(buf, "+Infinity");
2381 else if (isinf(cur->floatval) < 0)
2382 sprintf(buf, "-Infinity");
2383 else
2384 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002385 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002386 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002387 return;
2388 }
2389 }
2390 STRANGE
2391}
2392
2393/**
2394 * xmlXPathStringLengthFunction:
2395 * @ctxt: the XPath Parser context
2396 *
2397 * Implement the string-length() XPath function
2398 * The string-length returns the number of characters in the string
2399 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2400 * the context node converted to a string, in other words the value
2401 * of the context node.
2402 */
2403void
2404xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2405 xmlXPathObjectPtr cur;
2406
2407 if (nargs == 0) {
2408 if (ctxt->context->node == NULL) {
2409 valuePush(ctxt, xmlXPathNewFloat(0));
2410 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002411 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002412
2413 content = xmlNodeGetContent(ctxt->context->node);
2414 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002415 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002416 }
2417 return;
2418 }
2419 CHECK_ARITY(1);
2420 CHECK_TYPE(XPATH_STRING);
2421 cur = valuePop(ctxt);
2422 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2423 xmlXPathFreeObject(cur);
2424}
2425
2426/**
2427 * xmlXPathConcatFunction:
2428 * @ctxt: the XPath Parser context
2429 *
2430 * Implement the concat() XPath function
2431 * The concat function returns the concatenation of its arguments.
2432 */
2433void
2434xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2435 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002436 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002437
2438 if (nargs < 2) {
2439 CHECK_ARITY(2);
2440 }
2441
2442 cur = valuePop(ctxt);
2443 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2444 xmlXPathFreeObject(cur);
2445 return;
2446 }
2447 nargs--;
2448
2449 while (nargs > 0) {
2450 new = valuePop(ctxt);
2451 if ((new == NULL) || (new->type != XPATH_STRING)) {
2452 xmlXPathFreeObject(new);
2453 xmlXPathFreeObject(cur);
2454 ERROR(XPATH_INVALID_TYPE);
2455 }
2456 tmp = xmlStrcat(new->stringval, cur->stringval);
2457 new->stringval = cur->stringval;
2458 cur->stringval = tmp;
2459
2460 xmlXPathFreeObject(new);
2461 nargs--;
2462 }
2463 valuePush(ctxt, cur);
2464}
2465
2466/**
2467 * xmlXPathContainsFunction:
2468 * @ctxt: the XPath Parser context
2469 *
2470 * Implement the contains() XPath function
2471 * The contains function returns true if the first argument string
2472 * contains the second argument string, and otherwise returns false.
2473 */
2474void
2475xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2476 xmlXPathObjectPtr hay, needle;
2477
2478 CHECK_ARITY(2);
2479 CHECK_TYPE(XPATH_STRING);
2480 needle = valuePop(ctxt);
2481 hay = valuePop(ctxt);
2482 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2483 xmlXPathFreeObject(hay);
2484 xmlXPathFreeObject(needle);
2485 ERROR(XPATH_INVALID_TYPE);
2486 }
2487 if (xmlStrstr(hay->stringval, needle->stringval))
2488 valuePush(ctxt, xmlXPathNewBoolean(1));
2489 else
2490 valuePush(ctxt, xmlXPathNewBoolean(0));
2491 xmlXPathFreeObject(hay);
2492 xmlXPathFreeObject(needle);
2493}
2494
2495/**
2496 * xmlXPathStartsWithFunction:
2497 * @ctxt: the XPath Parser context
2498 *
2499 * Implement the starts-with() XPath function
2500 * The starts-with function returns true if the first argument string
2501 * starts with the second argument string, and otherwise returns false.
2502 */
2503void
2504xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2505 xmlXPathObjectPtr hay, needle;
2506 int n;
2507
2508 CHECK_ARITY(2);
2509 CHECK_TYPE(XPATH_STRING);
2510 needle = valuePop(ctxt);
2511 hay = valuePop(ctxt);
2512 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2513 xmlXPathFreeObject(hay);
2514 xmlXPathFreeObject(needle);
2515 ERROR(XPATH_INVALID_TYPE);
2516 }
2517 n = xmlStrlen(needle->stringval);
2518 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2519 valuePush(ctxt, xmlXPathNewBoolean(0));
2520 else
2521 valuePush(ctxt, xmlXPathNewBoolean(1));
2522 xmlXPathFreeObject(hay);
2523 xmlXPathFreeObject(needle);
2524}
2525
2526/**
2527 * xmlXPathSubstringFunction:
2528 * @ctxt: the XPath Parser context
2529 *
2530 * Implement the substring() XPath function
2531 * The substring function returns the substring of the first argument
2532 * starting at the position specified in the second argument with
2533 * length specified in the third argument. For example,
2534 * substring("12345",2,3) returns "234". If the third argument is not
2535 * specified, it returns the substring starting at the position specified
2536 * in the second argument and continuing to the end of the string. For
2537 * example, substring("12345",2) returns "2345". More precisely, each
2538 * character in the string (see [3.6 Strings]) is considered to have a
2539 * numeric position: the position of the first character is 1, the position
2540 * of the second character is 2 and so on. The returned substring contains
2541 * those characters for which the position of the character is greater than
2542 * or equal to the second argument and, if the third argument is specified,
2543 * less than the sum of the second and third arguments; the comparisons
2544 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2545 * - substring("12345", 1.5, 2.6) returns "234"
2546 * - substring("12345", 0, 3) returns "12"
2547 * - substring("12345", 0 div 0, 3) returns ""
2548 * - substring("12345", 1, 0 div 0) returns ""
2549 * - substring("12345", -42, 1 div 0) returns "12345"
2550 * - substring("12345", -1 div 0, 1 div 0) returns ""
2551 */
2552void
2553xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2554 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002555 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002556 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002557 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002558
2559 /*
2560 * Conformance needs to be checked !!!!!
2561 */
2562 if (nargs < 2) {
2563 CHECK_ARITY(2);
2564 }
2565 if (nargs > 3) {
2566 CHECK_ARITY(3);
2567 }
2568 if (nargs == 3) {
2569 CHECK_TYPE(XPATH_NUMBER);
2570 len = valuePop(ctxt);
2571 le = len->floatval;
2572 xmlXPathFreeObject(len);
2573 } else {
2574 le = 2000000000;
2575 }
2576 CHECK_TYPE(XPATH_NUMBER);
2577 start = valuePop(ctxt);
2578 in = start->floatval;
2579 xmlXPathFreeObject(start);
2580 CHECK_TYPE(XPATH_STRING);
2581 str = valuePop(ctxt);
2582 le += in;
2583
2584 /* integer index of the first char */
2585 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002586 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002587
2588 /* integer index of the last char */
2589 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002590 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002591
2592 /* back to a zero based len */
2593 i--;
2594 l--;
2595
2596 /* check against the string len */
2597 if (l > 1024) {
2598 l = xmlStrlen(str->stringval);
2599 }
2600 if (i < 0) {
2601 i = 0;
2602 }
2603
2604 /* number of chars to copy */
2605 l -= i;
2606
2607 ret = xmlStrsub(str->stringval, i, l);
2608 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002609 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002610 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002611 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002612 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002613 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002614 xmlXPathFreeObject(str);
2615}
2616
2617/**
2618 * xmlXPathSubstringBeforeFunction:
2619 * @ctxt: the XPath Parser context
2620 *
2621 * Implement the substring-before() XPath function
2622 * The substring-before function returns the substring of the first
2623 * argument string that precedes the first occurrence of the second
2624 * argument string in the first argument string, or the empty string
2625 * if the first argument string does not contain the second argument
2626 * string. For example, substring-before("1999/04/01","/") returns 1999.
2627 */
2628void
2629xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2630 CHECK_ARITY(2);
2631 TODO /* substring before */
2632}
2633
2634/**
2635 * xmlXPathSubstringAfterFunction:
2636 * @ctxt: the XPath Parser context
2637 *
2638 * Implement the substring-after() XPath function
2639 * The substring-after function returns the substring of the first
2640 * argument string that follows the first occurrence of the second
2641 * argument string in the first argument string, or the empty stringi
2642 * if the first argument string does not contain the second argument
2643 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2644 * and substring-after("1999/04/01","19") returns 99/04/01.
2645 */
2646void
2647xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2648 CHECK_ARITY(2);
2649 TODO /* substring after */
2650}
2651
2652/**
2653 * xmlXPathNormalizeFunction:
2654 * @ctxt: the XPath Parser context
2655 *
2656 * Implement the normalize() XPath function
2657 * The normalize function returns the argument string with white
2658 * space normalized by stripping leading and trailing whitespace
2659 * and replacing sequences of whitespace characters by a single
2660 * space. Whitespace characters are the same allowed by the S production
2661 * in XML. If the argument is omitted, it defaults to the context
2662 * node converted to a string, in other words the value of the context node.
2663 */
2664void
2665xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2666 CHECK_ARITY(1);
2667 TODO /* normalize isn't as boring as translate, but pretty much */
2668}
2669
2670/**
2671 * xmlXPathTranslateFunction:
2672 * @ctxt: the XPath Parser context
2673 *
2674 * Implement the translate() XPath function
2675 * The translate function returns the first argument string with
2676 * occurrences of characters in the second argument string replaced
2677 * by the character at the corresponding position in the third argument
2678 * string. For example, translate("bar","abc","ABC") returns the string
2679 * BAr. If there is a character in the second argument string with no
2680 * character at a corresponding position in the third argument string
2681 * (because the second argument string is longer than the third argument
2682 * string), then occurrences of that character in the first argument
2683 * string are removed. For example, translate("--aaa--","abc-","ABC")
2684 * returns "AAA". If a character occurs more than once in second
2685 * argument string, then the first occurrence determines the replacement
2686 * character. If the third argument string is longer than the second
2687 * argument string, then excess characters are ignored.
2688 */
2689void
2690xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2691 CHECK_ARITY(3);
2692 TODO /* translate is boring, waiting for UTF-8 representation too */
2693}
2694
2695/**
2696 * xmlXPathBooleanFunction:
2697 * @ctxt: the XPath Parser context
2698 *
2699 * Implement the boolean() XPath function
2700 * he boolean function converts its argument to a boolean as follows:
2701 * - a number is true if and only if it is neither positive or
2702 * negative zero nor NaN
2703 * - a node-set is true if and only if it is non-empty
2704 * - a string is true if and only if its length is non-zero
2705 */
2706void
2707xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2708 xmlXPathObjectPtr cur;
2709 int res = 0;
2710
2711 CHECK_ARITY(1);
2712 cur = valuePop(ctxt);
2713 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2714 switch (cur->type) {
2715 case XPATH_NODESET:
2716 if ((cur->nodesetval == NULL) ||
2717 (cur->nodesetval->nodeNr == 0)) res = 0;
2718 else
2719 res = 1;
2720 break;
2721 case XPATH_STRING:
2722 if ((cur->stringval == NULL) ||
2723 (cur->stringval[0] == 0)) res = 0;
2724 else
2725 res = 1;
2726 break;
2727 case XPATH_BOOLEAN:
2728 valuePush(ctxt, cur);
2729 return;
2730 case XPATH_NUMBER:
2731 if (cur->floatval) res = 1;
2732 break;
2733 default:
2734 STRANGE
2735 }
2736 xmlXPathFreeObject(cur);
2737 valuePush(ctxt, xmlXPathNewBoolean(res));
2738}
2739
2740/**
2741 * xmlXPathNotFunction:
2742 * @ctxt: the XPath Parser context
2743 *
2744 * Implement the not() XPath function
2745 * The not function returns true if its argument is false,
2746 * and false otherwise.
2747 */
2748void
2749xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2750 CHECK_ARITY(1);
2751 CHECK_TYPE(XPATH_BOOLEAN);
2752 ctxt->value->boolval = ! ctxt->value->boolval;
2753}
2754
2755/**
2756 * xmlXPathTrueFunction:
2757 * @ctxt: the XPath Parser context
2758 *
2759 * Implement the true() XPath function
2760 */
2761void
2762xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2763 CHECK_ARITY(0);
2764 valuePush(ctxt, xmlXPathNewBoolean(1));
2765}
2766
2767/**
2768 * xmlXPathFalseFunction:
2769 * @ctxt: the XPath Parser context
2770 *
2771 * Implement the false() XPath function
2772 */
2773void
2774xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2775 CHECK_ARITY(0);
2776 valuePush(ctxt, xmlXPathNewBoolean(0));
2777}
2778
2779/**
2780 * xmlXPathLangFunction:
2781 * @ctxt: the XPath Parser context
2782 *
2783 * Implement the lang() XPath function
2784 * The lang function returns true or false depending on whether the
2785 * language of the context node as specified by xml:lang attributes
2786 * is the same as or is a sublanguage of the language specified by
2787 * the argument string. The language of the context node is determined
2788 * by the value of the xml:lang attribute on the context node, or, if
2789 * the context node has no xml:lang attribute, by the value of the
2790 * xml:lang attribute on the nearest ancestor of the context node that
2791 * has an xml:lang attribute. If there is no such attribute, then lang
2792 * returns false. If there is such an attribute, then lang returns
2793 * true if the attribute value is equal to the argument ignoring case,
2794 * or if there is some suffix starting with - such that the attribute
2795 * value is equal to the argument ignoring that suffix of the attribute
2796 * value and ignoring case.
2797 */
2798void
2799xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002800 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002801 const xmlChar *theLang;
2802 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002803 int ret = 0;
2804 int i;
2805
2806 CHECK_ARITY(1);
2807 CHECK_TYPE(XPATH_STRING);
2808 val = valuePop(ctxt);
2809 lang = val->stringval;
2810 theLang = xmlNodeGetLang(ctxt->context->node);
2811 if ((theLang != NULL) && (lang != NULL)) {
2812 for (i = 0;lang[i] != 0;i++)
2813 if (toupper(lang[i]) != toupper(theLang[i]))
2814 goto not_equal;
2815 ret = 1;
2816 }
2817not_equal:
2818 xmlXPathFreeObject(val);
2819 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002820}
2821
2822/**
2823 * xmlXPathNumberFunction:
2824 * @ctxt: the XPath Parser context
2825 *
2826 * Implement the number() XPath function
2827 */
2828void
2829xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2830 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002831 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002832
2833 CHECK_ARITY(1);
2834 cur = valuePop(ctxt);
2835 switch (cur->type) {
2836 case XPATH_NODESET:
2837 valuePush(ctxt, cur);
2838 xmlXPathStringFunction(ctxt, 1);
2839 cur = valuePop(ctxt);
2840 case XPATH_STRING:
2841 res = xmlXPathStringEvalNumber(cur->stringval);
2842 valuePush(ctxt, xmlXPathNewFloat(res));
2843 xmlXPathFreeObject(cur);
2844 return;
2845 case XPATH_BOOLEAN:
2846 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2847 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2848 xmlXPathFreeObject(cur);
2849 return;
2850 case XPATH_NUMBER:
2851 valuePush(ctxt, cur);
2852 return;
2853 }
2854 STRANGE
2855}
2856
2857/**
2858 * xmlXPathSumFunction:
2859 * @ctxt: the XPath Parser context
2860 *
2861 * Implement the sum() XPath function
2862 * The sum function returns the sum of the values of the nodes in
2863 * the argument node-set.
2864 */
2865void
2866xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2867 CHECK_ARITY(1);
2868 TODO /* BUG Sum : don't understand the definition */
2869}
2870
2871/**
2872 * xmlXPathFloorFunction:
2873 * @ctxt: the XPath Parser context
2874 *
2875 * Implement the floor() XPath function
2876 * The floor function returns the largest (closest to positive infinity)
2877 * number that is not greater than the argument and that is an integer.
2878 */
2879void
2880xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2881 CHECK_ARITY(1);
2882 CHECK_TYPE(XPATH_NUMBER);
2883 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002884 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002885}
2886
2887/**
2888 * xmlXPathCeilingFunction:
2889 * @ctxt: the XPath Parser context
2890 *
2891 * Implement the ceiling() XPath function
2892 * The ceiling function returns the smallest (closest to negative infinity)
2893 * number that is not less than the argument and that is an integer.
2894 */
2895void
2896xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002897 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002898
2899 CHECK_ARITY(1);
2900 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002901 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002902 if (f != ctxt->value->floatval)
2903 ctxt->value->floatval = f + 1;
2904}
2905
2906/**
2907 * xmlXPathRoundFunction:
2908 * @ctxt: the XPath Parser context
2909 *
2910 * Implement the round() XPath function
2911 * The round function returns the number that is closest to the
2912 * argument and that is an integer. If there are two such numbers,
2913 * then the one that is even is returned.
2914 */
2915void
2916xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002917 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002918
2919 CHECK_ARITY(1);
2920 CHECK_TYPE(XPATH_NUMBER);
2921 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002922 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002923 if (ctxt->value->floatval < f + 0.5)
2924 ctxt->value->floatval = f;
2925 else if (ctxt->value->floatval == f + 0.5)
2926 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2927 else
2928 ctxt->value->floatval = f + 1;
2929}
2930
2931/************************************************************************
2932 * *
2933 * The Parser *
2934 * *
2935 ************************************************************************/
2936
2937/*
2938 * a couple of forward declarations since we use a recursive call based
2939 * implementation.
2940 */
2941void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2942void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2943void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2944void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2945
2946/**
2947 * xmlXPathParseNCName:
2948 * @ctxt: the XPath Parser context
2949 *
2950 * parse an XML namespace non qualified name.
2951 *
2952 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2953 *
2954 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2955 * CombiningChar | Extender
2956 *
2957 * Returns the namespace name or NULL
2958 */
2959
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002960xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002961xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002962 const xmlChar *q;
2963 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002964
2965 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2966 q = NEXT;
2967
2968 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2969 (CUR == '.') || (CUR == '-') ||
2970 (CUR == '_') ||
2971 (IS_COMBINING(CUR)) ||
2972 (IS_EXTENDER(CUR)))
2973 NEXT;
2974
2975 ret = xmlStrndup(q, CUR_PTR - q);
2976
2977 return(ret);
2978}
2979
2980/**
2981 * xmlXPathParseQName:
2982 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002983 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002984 *
2985 * parse an XML qualified name
2986 *
2987 * [NS 5] QName ::= (Prefix ':')? LocalPart
2988 *
2989 * [NS 6] Prefix ::= NCName
2990 *
2991 * [NS 7] LocalPart ::= NCName
2992 *
2993 * Returns the function returns the local part, and prefix is updated
2994 * to get the Prefix if any.
2995 */
2996
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002997xmlChar *
2998xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
2999 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003000
3001 *prefix = NULL;
3002 ret = xmlXPathParseNCName(ctxt);
3003 if (CUR == ':') {
3004 *prefix = ret;
3005 NEXT;
3006 ret = xmlXPathParseNCName(ctxt);
3007 }
3008 return(ret);
3009}
3010
3011/**
3012 * xmlXPathStringEvalNumber:
3013 * @str: A string to scan
3014 *
3015 * [30] Number ::= Digits ('.' Digits)?
3016 * | '.' Digits
3017 * [31] Digits ::= [0-9]+
3018 *
3019 * Parse and evaluate a Number in the string
3020 *
3021 * BUG: "1.' is not valid ... James promised correction
3022 * as Digits ('.' Digits?)?
3023 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003024 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003025 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003026double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003027xmlXPathStringEvalNumber(const xmlChar *str) {
3028 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003029 double ret = 0.0;
3030 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003031 int ok = 0;
3032
3033 while (*cur == ' ') cur++;
3034 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003035 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003036 }
3037 while ((*cur >= '0') && (*cur <= '9')) {
3038 ret = ret * 10 + (*cur - '0');
3039 ok = 1;
3040 cur++;
3041 }
3042 if (*cur == '.') {
3043 cur++;
3044 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003045 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003046 }
3047 while ((*cur >= '0') && (*cur <= '9')) {
3048 mult /= 10;
3049 ret = ret + (*cur - '0') * mult;
3050 cur++;
3051 }
3052 }
3053 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003054 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003055 return(ret);
3056}
3057
3058/**
3059 * xmlXPathEvalNumber:
3060 * @ctxt: the XPath Parser context
3061 *
3062 * [30] Number ::= Digits ('.' Digits)?
3063 * | '.' Digits
3064 * [31] Digits ::= [0-9]+
3065 *
3066 * Parse and evaluate a Number, then push it on the stack
3067 *
3068 * BUG: "1.' is not valid ... James promised correction
3069 * as Digits ('.' Digits?)?
3070 */
3071void
3072xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003073 double ret = 0.0;
3074 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003075 int ok = 0;
3076
3077 CHECK_ERROR;
3078 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3079 ERROR(XPATH_NUMBER_ERROR);
3080 }
3081 while ((CUR >= '0') && (CUR <= '9')) {
3082 ret = ret * 10 + (CUR - '0');
3083 ok = 1;
3084 NEXT;
3085 }
3086 if (CUR == '.') {
3087 NEXT;
3088 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3089 ERROR(XPATH_NUMBER_ERROR);
3090 }
3091 while ((CUR >= '0') && (CUR <= '9')) {
3092 mult /= 10;
3093 ret = ret + (CUR - '0') * mult;
3094 NEXT;
3095 }
3096 }
3097 valuePush(ctxt, xmlXPathNewFloat(ret));
3098}
3099
3100/**
3101 * xmlXPathEvalLiteral:
3102 * @ctxt: the XPath Parser context
3103 *
3104 * Parse a Literal and push it on the stack.
3105 *
3106 * [29] Literal ::= '"' [^"]* '"'
3107 * | "'" [^']* "'"
3108 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003109 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003110 */
3111void
3112xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003113 const xmlChar *q;
3114 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003115
3116 if (CUR == '"') {
3117 NEXT;
3118 q = CUR_PTR;
3119 while ((IS_CHAR(CUR)) && (CUR != '"'))
3120 NEXT;
3121 if (!IS_CHAR(CUR)) {
3122 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3123 } else {
3124 ret = xmlStrndup(q, CUR_PTR - q);
3125 NEXT;
3126 }
3127 } else if (CUR == '\'') {
3128 NEXT;
3129 q = CUR_PTR;
3130 while ((IS_CHAR(CUR)) && (CUR != '\''))
3131 NEXT;
3132 if (!IS_CHAR(CUR)) {
3133 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3134 } else {
3135 ret = xmlStrndup(q, CUR_PTR - q);
3136 NEXT;
3137 }
3138 } else {
3139 ERROR(XPATH_START_LITERAL_ERROR);
3140 }
3141 if (ret == NULL) return;
3142 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003143 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003144}
3145
3146/**
3147 * xmlXPathEvalVariableReference:
3148 * @ctxt: the XPath Parser context
3149 *
3150 * Parse a VariableReference, evaluate it and push it on the stack.
3151 *
3152 * The variable bindings consist of a mapping from variable names
3153 * to variable values. The value of a variable is an object, which
3154 * of any of the types that are possible for the value of an expression,
3155 * and may also be of additional types not specified here.
3156 *
3157 * Early evaluation is possible since:
3158 * The variable bindings [...] used to evaluate a subexpression are
3159 * always the same as those used to evaluate the containing expression.
3160 *
3161 * [36] VariableReference ::= '$' QName
3162 */
3163void
3164xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003165 xmlChar *name;
3166 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003167 xmlXPathObjectPtr value;
3168
3169 if (CUR != '$') {
3170 ERROR(XPATH_VARIABLE_REF_ERROR);
3171 }
3172 name = xmlXPathParseQName(ctxt, &prefix);
3173 if (name == NULL) {
3174 ERROR(XPATH_VARIABLE_REF_ERROR);
3175 }
3176 value = xmlXPathVariablelookup(ctxt, prefix, name);
3177 if (value == NULL) {
3178 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3179 }
3180 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003181 if (prefix != NULL) xmlFree(prefix);
3182 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003183}
3184
3185
3186/**
3187 * xmlXPathFunctionLookup:
3188 * @ctxt: the XPath Parser context
3189 * @name: a name string
3190 *
3191 * Search for a function of the given name
3192 *
3193 * [35] FunctionName ::= QName - NodeType
3194 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003195 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003196 *
3197 * Returns the xmlXPathFunction if found, or NULL otherwise
3198 */
3199xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003200xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003201 switch (name[0]) {
3202 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003203 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003204 return(xmlXPathBooleanFunction);
3205 break;
3206 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003207 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003208 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003209 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003210 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003211 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003212 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003213 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003214 return(xmlXPathContainsFunction);
3215 break;
3216 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003217 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003218 return(xmlXPathIdFunction);
3219 break;
3220 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003221 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003222 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003223 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003224 return(xmlXPathFloorFunction);
3225 break;
3226 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003227 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003228 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003229 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003230 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003231 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003232 return(xmlXPathLocalPartFunction);
3233 break;
3234 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003235 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003236 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003237 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003238 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003239 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003240 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003241 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3242 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003243 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003244 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003245 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003246 return(xmlXPathNumberFunction);
3247 break;
3248 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003249 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003250 return(xmlXPathPositionFunction);
3251 break;
3252 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003253 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003254 return(xmlXPathRoundFunction);
3255 break;
3256 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003257 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003258 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003259 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003260 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003261 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003262 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003263 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003264 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003265 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003266 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003267 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003268 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003269 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003270 return(xmlXPathSumFunction);
3271 break;
3272 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003273 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003274 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003275 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003276 return(xmlXPathTranslateFunction);
3277 break;
3278 }
3279 return(NULL);
3280}
3281
3282/**
3283 * xmlXPathEvalLocationPathName:
3284 * @ctxt: the XPath Parser context
3285 * @name: a name string
3286 *
3287 * Various names in the beginning of a LocationPath expression
3288 * indicate whether that's an Axis, a node type,
3289 *
3290 * [6] AxisName ::= 'ancestor'
3291 * | 'ancestor-or-self'
3292 * | 'attribute'
3293 * | 'child'
3294 * | 'descendant'
3295 * | 'descendant-or-self'
3296 * | 'following'
3297 * | 'following-sibling'
3298 * | 'namespace'
3299 * | 'parent'
3300 * | 'preceding'
3301 * | 'preceding-sibling'
3302 * | 'self'
3303 * [38] NodeType ::= 'comment'
3304 * | 'text'
3305 * | 'processing-instruction'
3306 * | 'node'
3307 */
3308int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003309xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003310 switch (name[0]) {
3311 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003312 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3313 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3314 return(AXIS_ANCESTOR_OR_SELF);
3315 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003316 break;
3317 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003318 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3319 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003320 break;
3321 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003322 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3323 return(AXIS_DESCENDANT);
3324 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3325 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003326 break;
3327 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003328 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3329 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3330 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003331 break;
3332 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003333 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3334 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003335 break;
3336 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003337 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3338 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3339 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3340 return(AXIS_PRECEDING_SIBLING);
3341 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3342 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003343 break;
3344 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003345 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 break;
3347 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003348 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003349 break;
3350 }
3351 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3352 return(0);
3353}
3354
3355/**
3356 * xmlXPathEvalFunctionCall:
3357 * @ctxt: the XPath Parser context
3358 *
3359 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3360 * [17] Argument ::= Expr
3361 *
3362 * Parse and evaluate a function call, the evaluation of all arguments are
3363 * pushed on the stack
3364 */
3365void
3366xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003367 xmlChar *name;
3368 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003369 xmlXPathFunction func;
3370 int nbargs = 0;
3371
3372 name = xmlXPathParseQName(ctxt, &prefix);
3373 if (name == NULL) {
3374 ERROR(XPATH_EXPR_ERROR);
3375 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003376 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003377 func = xmlXPathIsFunction(ctxt, name);
3378 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003379 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003380 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3381 }
3382#ifdef DEBUG_EXPR
3383 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3384#endif
3385
3386 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003387 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003388 ERROR(XPATH_EXPR_ERROR);
3389 }
3390 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003391 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003392
3393 while (CUR != ')') {
3394 xmlXPathEvalExpr(ctxt);
3395 nbargs++;
3396 if (CUR == ')') break;
3397 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003398 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003399 ERROR(XPATH_EXPR_ERROR);
3400 }
3401 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003402 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003403 }
3404 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003405 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003406 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003407 func(ctxt, nbargs);
3408}
3409
3410/**
3411 * xmlXPathEvalPrimaryExpr:
3412 * @ctxt: the XPath Parser context
3413 *
3414 * [15] PrimaryExpr ::= VariableReference
3415 * | '(' Expr ')'
3416 * | Literal
3417 * | Number
3418 * | FunctionCall
3419 *
3420 * Parse and evaluate a primary expression, then push the result on the stack
3421 */
3422void
3423xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003424 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003425 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3426 else if (CUR == '(') {
3427 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003428 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003429 xmlXPathEvalExpr(ctxt);
3430 if (CUR != ')') {
3431 ERROR(XPATH_EXPR_ERROR);
3432 }
3433 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003434 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003435 } else if (IS_DIGIT(CUR)) {
3436 xmlXPathEvalNumber(ctxt);
3437 } else if ((CUR == '\'') || (CUR == '"')) {
3438 xmlXPathEvalLiteral(ctxt);
3439 } else {
3440 xmlXPathEvalFunctionCall(ctxt);
3441 }
3442}
3443
3444/**
3445 * xmlXPathEvalFilterExpr:
3446 * @ctxt: the XPath Parser context
3447 *
3448 * [20] FilterExpr ::= PrimaryExpr
3449 * | FilterExpr Predicate
3450 *
3451 * Parse and evaluate a filter expression, then push the result on the stack
3452 * Square brackets are used to filter expressions in the same way that
3453 * they are used in location paths. It is an error if the expression to
3454 * be filtered does not evaluate to a node-set. The context node list
3455 * used for evaluating the expression in square brackets is the node-set
3456 * to be filtered listed in document order.
3457 */
3458
3459void
3460xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3461 /****
3462 xmlNodeSetPtr oldset = NULL;
3463 xmlXPathObjectPtr arg;
3464 ****/
3465
3466 xmlXPathEvalPrimaryExpr(ctxt);
3467 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003468 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003469
3470 if (CUR != '[') return;
3471
3472 CHECK_TYPE(XPATH_NODESET);
3473
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003474 while (CUR == '[') {
3475 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003476 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003477 }
3478
3479
3480}
3481
3482/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003483 * xmlXPathScanName:
3484 * @ctxt: the XPath Parser context
3485 *
3486 * Trickery: parse an XML name but without consuming the input flow
3487 * Needed for rollback cases.
3488 *
3489 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3490 * CombiningChar | Extender
3491 *
3492 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3493 *
3494 * [6] Names ::= Name (S Name)*
3495 *
3496 * Returns the Name parsed or NULL
3497 */
3498
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003499xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003500xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003501 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003502 int len = 0;
3503
Daniel Veillard00fdf371999-10-08 09:40:39 +00003504 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003505 if (!IS_LETTER(CUR) && (CUR != '_') &&
3506 (CUR != ':')) {
3507 return(NULL);
3508 }
3509
3510 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3511 (NXT(len) == '.') || (NXT(len) == '-') ||
3512 (NXT(len) == '_') || (NXT(len) == ':') ||
3513 (IS_COMBINING(NXT(len))) ||
3514 (IS_EXTENDER(NXT(len)))) {
3515 buf[len] = NXT(len);
3516 len++;
3517 if (len >= XML_MAX_NAMELEN) {
3518 fprintf(stderr,
3519 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3520 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3521 (NXT(len) == '.') || (NXT(len) == '-') ||
3522 (NXT(len) == '_') || (NXT(len) == ':') ||
3523 (IS_COMBINING(NXT(len))) ||
3524 (IS_EXTENDER(NXT(len))))
3525 len++;
3526 break;
3527 }
3528 }
3529 return(xmlStrndup(buf, len));
3530}
3531
3532/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003533 * xmlXPathEvalPathExpr:
3534 * @ctxt: the XPath Parser context
3535 *
3536 * [19] PathExpr ::= LocationPath
3537 * | FilterExpr
3538 * | FilterExpr '/' RelativeLocationPath
3539 * | FilterExpr '//' RelativeLocationPath
3540 *
3541 * Parse and evaluate a path expression, then push the result on the stack
3542 * The / operator and // operators combine an arbitrary expression
3543 * and a relative location path. It is an error if the expression
3544 * does not evaluate to a node-set.
3545 * The / operator does composition in the same way as when / is
3546 * used in a location path. As in location paths, // is short for
3547 * /descendant-or-self::node()/.
3548 */
3549
3550void
3551xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3552 xmlNodeSetPtr newset = NULL;
3553
Daniel Veillard00fdf371999-10-08 09:40:39 +00003554 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003555 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3556 (CUR == '\'') || (CUR == '"')) {
3557 xmlXPathEvalFilterExpr(ctxt);
3558 CHECK_ERROR;
3559 if ((CUR == '/') && (NXT(1) == '/')) {
3560 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003561 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003562 if (ctxt->context->nodelist == NULL) {
3563 STRANGE
3564 xmlXPathRoot(ctxt);
3565 }
3566 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3567 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3568 if (ctxt->context->nodelist != NULL)
3569 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3570 ctxt->context->nodelist = newset;
3571 ctxt->context->node = NULL;
3572 xmlXPathEvalRelativeLocationPath(ctxt);
3573 } else if (CUR == '/') {
3574 xmlXPathEvalRelativeLocationPath(ctxt);
3575 }
3576 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003577 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003578 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003579
3580 name = xmlXPathScanName(ctxt);
3581 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3582 xmlXPathEvalLocationPath(ctxt);
3583 else
3584 xmlXPathEvalFilterExpr(ctxt);
3585 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003586 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003587 }
3588}
3589
3590/**
3591 * xmlXPathEvalUnionExpr:
3592 * @ctxt: the XPath Parser context
3593 *
3594 * [18] UnionExpr ::= PathExpr
3595 * | UnionExpr '|' PathExpr
3596 *
3597 * Parse and evaluate an union expression, then push the result on the stack
3598 */
3599
3600void
3601xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3602 xmlXPathEvalPathExpr(ctxt);
3603 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003604 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003605 if (CUR == '|') {
3606 xmlNodeSetPtr old = ctxt->context->nodelist;
3607
Daniel Veillard00fdf371999-10-08 09:40:39 +00003608 NEXT;
3609 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003610 xmlXPathEvalPathExpr(ctxt);
3611
3612 if (ctxt->context->nodelist == NULL)
3613 ctxt->context->nodelist = old;
3614 else {
3615 ctxt->context->nodelist =
3616 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3617 xmlXPathFreeNodeSet(old);
3618 }
3619 }
3620}
3621
3622/**
3623 * xmlXPathEvalUnaryExpr:
3624 * @ctxt: the XPath Parser context
3625 *
3626 * [27] UnaryExpr ::= UnionExpr
3627 * | '-' UnaryExpr
3628 *
3629 * Parse and evaluate an unary expression, then push the result on the stack
3630 */
3631
3632void
3633xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3634 int minus = 0;
3635
Daniel Veillard00fdf371999-10-08 09:40:39 +00003636 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003637 if (CUR == '-') {
3638 minus = 1;
3639 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003640 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003641 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003642 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003643 CHECK_ERROR;
3644 if (minus) {
3645 xmlXPathValueFlipSign(ctxt);
3646 }
3647}
3648
3649/**
3650 * xmlXPathEvalMultiplicativeExpr:
3651 * @ctxt: the XPath Parser context
3652 *
3653 * [26] MultiplicativeExpr ::= UnaryExpr
3654 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3655 * | MultiplicativeExpr 'div' UnaryExpr
3656 * | MultiplicativeExpr 'mod' UnaryExpr
3657 * [34] MultiplyOperator ::= '*'
3658 *
3659 * Parse and evaluate an Additive expression, then push the result on the stack
3660 */
3661
3662void
3663xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3664 xmlXPathEvalUnaryExpr(ctxt);
3665 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003666 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003667 while ((CUR == '*') ||
3668 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3669 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3670 int op = -1;
3671
3672 if (CUR == '*') {
3673 op = 0;
3674 NEXT;
3675 } else if (CUR == 'd') {
3676 op = 1;
3677 SKIP(3);
3678 } else if (CUR == 'm') {
3679 op = 2;
3680 SKIP(3);
3681 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003682 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003683 xmlXPathEvalUnaryExpr(ctxt);
3684 CHECK_ERROR;
3685 switch (op) {
3686 case 0:
3687 xmlXPathMultValues(ctxt);
3688 break;
3689 case 1:
3690 xmlXPathDivValues(ctxt);
3691 break;
3692 case 2:
3693 xmlXPathModValues(ctxt);
3694 break;
3695 }
3696 }
3697}
3698
3699/**
3700 * xmlXPathEvalAdditiveExpr:
3701 * @ctxt: the XPath Parser context
3702 *
3703 * [25] AdditiveExpr ::= MultiplicativeExpr
3704 * | AdditiveExpr '+' MultiplicativeExpr
3705 * | AdditiveExpr '-' MultiplicativeExpr
3706 *
3707 * Parse and evaluate an Additive expression, then push the result on the stack
3708 */
3709
3710void
3711xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3712 xmlXPathEvalMultiplicativeExpr(ctxt);
3713 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003714 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003715 while ((CUR == '+') || (CUR == '-')) {
3716 int plus;
3717
3718 if (CUR == '+') plus = 1;
3719 else plus = 0;
3720 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003721 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003722 xmlXPathEvalMultiplicativeExpr(ctxt);
3723 CHECK_ERROR;
3724 if (plus) xmlXPathAddValues(ctxt);
3725 else xmlXPathSubValues(ctxt);
3726 }
3727}
3728
3729/**
3730 * xmlXPathEvalRelationalExpr:
3731 * @ctxt: the XPath Parser context
3732 *
3733 * [24] RelationalExpr ::= AdditiveExpr
3734 * | RelationalExpr '<' AdditiveExpr
3735 * | RelationalExpr '>' AdditiveExpr
3736 * | RelationalExpr '<=' AdditiveExpr
3737 * | RelationalExpr '>=' AdditiveExpr
3738 *
3739 * A <= B > C is allowed ? Answer from James, yes with
3740 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3741 * which is basically what got implemented.
3742 *
3743 * Parse and evaluate a Relational expression, then push the result
3744 * on the stack
3745 */
3746
3747void
3748xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3749 xmlXPathEvalAdditiveExpr(ctxt);
3750 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003751 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003752 while ((CUR == '<') ||
3753 (CUR == '>') ||
3754 ((CUR == '<') && (NXT(1) == '=')) ||
3755 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003756 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003757
3758 if (CUR == '<') inf = 1;
3759 else inf = 0;
3760 if (NXT(1) == '=') strict = 0;
3761 else strict = 1;
3762 NEXT;
3763 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003764 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003765 xmlXPathEvalAdditiveExpr(ctxt);
3766 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003767 ret = xmlXPathCompareValues(ctxt, inf, strict);
3768 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003769 }
3770}
3771
3772/**
3773 * xmlXPathEvalEqualityExpr:
3774 * @ctxt: the XPath Parser context
3775 *
3776 * [23] EqualityExpr ::= RelationalExpr
3777 * | EqualityExpr '=' RelationalExpr
3778 * | EqualityExpr '!=' RelationalExpr
3779 *
3780 * A != B != C is allowed ? Answer from James, yes with
3781 * (RelationalExpr = RelationalExpr) = RelationalExpr
3782 * (RelationalExpr != RelationalExpr) != RelationalExpr
3783 * which is basically what got implemented.
3784 *
3785 * Parse and evaluate an Equality expression, then push the result on the stack
3786 *
3787 */
3788void
3789xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3790 xmlXPathEvalRelationalExpr(ctxt);
3791 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003792 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003793 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003794 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003795 int eq, equal;
3796
3797 if (CUR == '=') eq = 1;
3798 else eq = 0;
3799 NEXT;
3800 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003801 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003802 xmlXPathEvalRelationalExpr(ctxt);
3803 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003804 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003805 if (eq) res = xmlXPathNewBoolean(equal);
3806 else res = xmlXPathNewBoolean(!equal);
3807 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003808 }
3809}
3810
3811/**
3812 * xmlXPathEvalAndExpr:
3813 * @ctxt: the XPath Parser context
3814 *
3815 * [22] AndExpr ::= EqualityExpr
3816 * | AndExpr 'and' EqualityExpr
3817 *
3818 * Parse and evaluate an AND expression, then push the result on the stack
3819 *
3820 */
3821void
3822xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3823 xmlXPathEvalEqualityExpr(ctxt);
3824 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003825 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003826 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3827 xmlXPathObjectPtr arg1, arg2;
3828
3829 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003830 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003831 xmlXPathEvalEqualityExpr(ctxt);
3832 CHECK_ERROR;
3833 arg2 = valuePop(ctxt);
3834 arg1 = valuePop(ctxt);
3835 arg1->boolval &= arg2->boolval;
3836 valuePush(ctxt, arg1);
3837 xmlXPathFreeObject(arg2);
3838 }
3839}
3840
3841/**
3842 * xmlXPathEvalExpr:
3843 * @ctxt: the XPath Parser context
3844 *
3845 * [14] Expr ::= OrExpr
3846 * [21] OrExpr ::= AndExpr
3847 * | OrExpr 'or' AndExpr
3848 *
3849 * Parse and evaluate an expression, then push the result on the stack
3850 *
3851 */
3852void
3853xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3854 xmlXPathEvalAndExpr(ctxt);
3855 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003856 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003857 while ((CUR == 'o') && (NXT(1) == 'r')) {
3858 xmlXPathObjectPtr arg1, arg2;
3859
3860 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003861 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003862 xmlXPathEvalAndExpr(ctxt);
3863 CHECK_ERROR;
3864 arg2 = valuePop(ctxt);
3865 arg1 = valuePop(ctxt);
3866 arg1->boolval |= arg2->boolval;
3867 valuePush(ctxt, arg1);
3868 xmlXPathFreeObject(arg2);
3869 }
3870}
3871
3872/**
3873 * xmlXPathEvaluatePredicateResult:
3874 * @ctxt: the XPath Parser context
3875 * @res: the Predicate Expression evaluation result
3876 * @index: index of the current node in the current list
3877 *
3878 * Evaluate a predicate result for the current node.
3879 * A PredicateExpr is evaluated by evaluating the Expr and converting
3880 * the result to a boolean. If the result is a number, the result will
3881 * be converted to true if the number is equal to the position of the
3882 * context node in the context node list (as returned by the position
3883 * function) and will be converted to false otherwise; if the result
3884 * is not a number, then the result will be converted as if by a call
3885 * to the boolean function.
3886 */
3887int
3888xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3889 xmlXPathObjectPtr res, int index) {
3890 if (res == NULL) return(0);
3891 switch (res->type) {
3892 case XPATH_BOOLEAN:
3893 return(res->boolval);
3894 case XPATH_NUMBER:
3895 return(res->floatval == index);
3896 case XPATH_NODESET:
3897 return(res->nodesetval->nodeNr != 0);
3898 case XPATH_STRING:
3899 return((res->stringval != NULL) &&
3900 (xmlStrlen(res->stringval) != 0));
3901 default:
3902 STRANGE
3903 }
3904 return(0);
3905}
3906
3907/**
3908 * xmlXPathEvalPredicate:
3909 * @ctxt: the XPath Parser context
3910 *
3911 * [8] Predicate ::= '[' PredicateExpr ']'
3912 * [9] PredicateExpr ::= Expr
3913 *
3914 * Parse and evaluate a predicate for all the elements of the
3915 * current node list. Then refine the list by removing all
3916 * nodes where the predicate is false.
3917 */
3918void
3919xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003920 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003921 xmlXPathObjectPtr res;
3922 xmlNodeSetPtr newset = NULL;
3923 int i;
3924
Daniel Veillard00fdf371999-10-08 09:40:39 +00003925 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003926 if (CUR != '[') {
3927 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3928 }
3929 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003930 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003931 if ((ctxt->context->nodelist == NULL) ||
3932 (ctxt->context->nodelist->nodeNr == 0)) {
3933 ctxt->context->node = NULL;
3934 xmlXPathEvalExpr(ctxt);
3935 CHECK_ERROR;
3936 res = valuePop(ctxt);
3937 if (res != NULL)
3938 xmlXPathFreeObject(res);
3939 } else {
3940 cur = ctxt->cur;
3941 newset = xmlXPathNodeSetCreate(NULL);
3942 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3943 ctxt->cur = cur;
3944 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3945 xmlXPathEvalExpr(ctxt);
3946 CHECK_ERROR;
3947 res = valuePop(ctxt);
3948 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3949 xmlXPathNodeSetAdd(newset,
3950 ctxt->context->nodelist->nodeTab[i]);
3951 if (res != NULL)
3952 xmlXPathFreeObject(res);
3953 }
3954 if (ctxt->context->nodelist != NULL)
3955 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3956 ctxt->context->nodelist = newset;
3957 ctxt->context->node = NULL;
3958 }
3959 if (CUR != ']') {
3960 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3961 }
3962 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003963 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003964#ifdef DEBUG_STEP
3965 fprintf(xmlXPathDebug, "After predicate : ");
3966 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3967#endif
3968}
3969
3970/**
3971 * xmlXPathEvalBasis:
3972 * @ctxt: the XPath Parser context
3973 *
3974 * [5] Basis ::= AxisName '::' NodeTest
3975 * | AbbreviatedBasis
3976 * [13] AbbreviatedBasis ::= NodeTest
3977 * | '@' NodeTest
3978 * [7] NodeTest ::= WildcardName
3979 * | NodeType '(' ')'
3980 * | 'processing-instruction' '(' Literal ')'
3981 * [37] WildcardName ::= '*'
3982 * | NCName ':' '*'
3983 * | QName
3984 *
3985 * Evaluate one step in a Location Path
3986 */
3987void
3988xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003989 xmlChar *name = NULL;
3990 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003991 int type = 0;
3992 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
3993 int nodetest = NODE_TEST_NONE;
3994 int nodetype = 0;
3995 xmlNodeSetPtr newset = NULL;
3996
3997 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003998 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003999 axis = AXIS_ATTRIBUTE;
4000 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004001 } else if (CUR == '*') {
4002 NEXT;
4003 nodetest = NODE_TEST_ALL;
4004 } else {
4005 name = xmlXPathParseNCName(ctxt);
4006 if (name == NULL) {
4007 ERROR(XPATH_EXPR_ERROR);
4008 }
4009 type = xmlXPathGetNameType(ctxt, name);
4010 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004011 case IS_FUNCTION: {
4012 xmlXPathFunction func;
4013 int nbargs = 0;
4014 xmlXPathObjectPtr top;
4015
4016 top = ctxt->value;
4017 func = xmlXPathIsFunction(ctxt, name);
4018 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004019 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004020 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4021 }
4022#ifdef DEBUG_EXPR
4023 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4024#endif
4025
4026 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004027 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004028 ERROR(XPATH_EXPR_ERROR);
4029 }
4030 NEXT;
4031
4032 while (CUR != ')') {
4033 xmlXPathEvalExpr(ctxt);
4034 nbargs++;
4035 if (CUR == ')') break;
4036 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004037 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004038 ERROR(XPATH_EXPR_ERROR);
4039 }
4040 NEXT;
4041 }
4042 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004043 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004044 func(ctxt, nbargs);
4045 if ((ctxt->value != top) &&
4046 (ctxt->value != NULL) &&
4047 (ctxt->value->type == XPATH_NODESET)) {
4048 xmlXPathObjectPtr cur;
4049
4050 cur = valuePop(ctxt);
4051 ctxt->context->nodelist = cur->nodesetval;
4052 ctxt->context->node = NULL;
4053 cur->nodesetval = NULL;
4054 xmlXPathFreeObject(cur);
4055 }
4056 return;
4057 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004058 /*
4059 * Simple case: no axis seach all given node types.
4060 */
4061 case NODE_TYPE_COMMENT:
4062 if ((CUR != '(') || (NXT(1) != ')')) break;
4063 SKIP(2);
4064 nodetest = NODE_TEST_TYPE;
4065 nodetype = XML_COMMENT_NODE;
4066 goto search_nodes;
4067 case NODE_TYPE_TEXT:
4068 if ((CUR != '(') || (NXT(1) != ')')) break;
4069 SKIP(2);
4070 nodetest = NODE_TEST_TYPE;
4071 nodetype = XML_TEXT_NODE;
4072 goto search_nodes;
4073 case NODE_TYPE_NODE:
4074 if ((CUR != '(') || (NXT(1) != ')')) {
4075 nodetest = NODE_TEST_NAME;
4076 break;
4077 }
4078 SKIP(2);
4079 nodetest = NODE_TEST_TYPE;
4080 nodetype = XML_ELEMENT_NODE;
4081 goto search_nodes;
4082 case NODE_TYPE_PI:
4083 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004084 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004085 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004086 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004087 xmlXPathObjectPtr cur;
4088
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004089 /*
4090 * Specific case: search a PI by name.
4091 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004092 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004093 nodetest = NODE_TEST_PI;
4094 xmlXPathEvalLiteral(ctxt);
4095 CHECK_ERROR;
4096 if (CUR != ')')
4097 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004098 NEXT;
4099 xmlXPathStringFunction(ctxt, 1);
4100 CHECK_ERROR;
4101 cur = valuePop(ctxt);
4102 name = xmlStrdup(cur->stringval);
4103 xmlXPathFreeObject(cur);
4104 } else
4105 SKIP(2);
4106 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004107 goto search_nodes;
4108
4109 /*
4110 * Handling of the compund form: got the axis.
4111 */
4112 case AXIS_ANCESTOR:
4113 case AXIS_ANCESTOR_OR_SELF:
4114 case AXIS_ATTRIBUTE:
4115 case AXIS_CHILD:
4116 case AXIS_DESCENDANT:
4117 case AXIS_DESCENDANT_OR_SELF:
4118 case AXIS_FOLLOWING:
4119 case AXIS_FOLLOWING_SIBLING:
4120 case AXIS_NAMESPACE:
4121 case AXIS_PARENT:
4122 case AXIS_PRECEDING:
4123 case AXIS_PRECEDING_SIBLING:
4124 case AXIS_SELF:
4125 if ((CUR != ':') || (NXT(1) != ':')) {
4126 nodetest = NODE_TEST_NAME;
4127 break;
4128 }
4129 SKIP(2);
4130 axis = type;
4131 break;
4132
4133 /*
4134 * Default: abbreviated syntax the axis is AXIS_CHILD
4135 */
4136 default:
4137 nodetest = NODE_TEST_NAME;
4138 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004139parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004140 if (nodetest == NODE_TEST_NONE) {
4141 if (CUR == '*') {
4142 NEXT;
4143 nodetest = NODE_TEST_ALL;
4144 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004145 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004146 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004147 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004148 if (name == NULL) {
4149 ERROR(XPATH_EXPR_ERROR);
4150 }
4151 type = xmlXPathGetNameType(ctxt, name);
4152 switch (type) {
4153 /*
4154 * Simple case: no axis seach all given node types.
4155 */
4156 case NODE_TYPE_COMMENT:
4157 if ((CUR != '(') || (NXT(1) != ')')) break;
4158 SKIP(2);
4159 nodetest = NODE_TEST_TYPE;
4160 nodetype = XML_COMMENT_NODE;
4161 goto search_nodes;
4162 case NODE_TYPE_TEXT:
4163 if ((CUR != '(') || (NXT(1) != ')')) break;
4164 SKIP(2);
4165 nodetest = NODE_TEST_TYPE;
4166 nodetype = XML_TEXT_NODE;
4167 goto search_nodes;
4168 case NODE_TYPE_NODE:
4169 if ((CUR != '(') || (NXT(1) != ')')) {
4170 nodetest = NODE_TEST_NAME;
4171 break;
4172 }
4173 SKIP(2);
4174 nodetest = NODE_TEST_TYPE;
4175 nodetype = XML_ELEMENT_NODE;
4176 goto search_nodes;
4177 case NODE_TYPE_PI:
4178 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004179 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004180 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004181 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004182 xmlXPathObjectPtr cur;
4183
Daniel Veillardb05deb71999-08-10 19:04:08 +00004184 /*
4185 * Specific case: search a PI by name.
4186 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004187 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004188 nodetest = NODE_TEST_PI;
4189 xmlXPathEvalLiteral(ctxt);
4190 CHECK_ERROR;
4191 if (CUR != ')')
4192 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004193 NEXT;
4194 xmlXPathStringFunction(ctxt, 1);
4195 CHECK_ERROR;
4196 cur = valuePop(ctxt);
4197 name = xmlStrdup(cur->stringval);
4198 xmlXPathFreeObject(cur);
4199 } else
4200 SKIP(2);
4201 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004202 goto search_nodes;
4203 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004204 nodetest = NODE_TEST_NAME;
4205 }
4206 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4207 NEXT;
4208 prefix = name;
4209 if (CUR == '*') {
4210 NEXT;
4211 nodetest = NODE_TEST_ALL;
4212 } else
4213 name = xmlXPathParseNCName(ctxt);
4214 } else if (name == NULL)
4215 ERROR(XPATH_EXPR_ERROR);
4216 }
4217
4218search_nodes:
4219
4220#ifdef DEBUG_STEP
4221 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4222#endif
4223 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4224 prefix, name);
4225 if (ctxt->context->nodelist != NULL)
4226 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4227 ctxt->context->nodelist = newset;
4228 ctxt->context->node = NULL;
4229#ifdef DEBUG_STEP
4230 fprintf(xmlXPathDebug, "Basis : ");
4231 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4232#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004233 if (name != NULL) xmlFree(name);
4234 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004235}
4236
4237/**
4238 * xmlXPathEvalStep:
4239 * @ctxt: the XPath Parser context
4240 *
4241 * [4] Step ::= Basis Predicate*
4242 * | AbbreviatedStep
4243 * [12] AbbreviatedStep ::= '.'
4244 * | '..'
4245 *
4246 * Evaluate one step in a Location Path
4247 * A location step of . is short for self::node(). This is
4248 * particularly useful in conjunction with //. For example, the
4249 * location path .//para is short for
4250 * self::node()/descendant-or-self::node()/child::para
4251 * and so will select all para descendant elements of the context
4252 * node.
4253 * Similarly, a location step of .. is short for parent::node().
4254 * For example, ../title is short for parent::node()/child::title
4255 * and so will select the title children of the parent of the context
4256 * node.
4257 */
4258void
4259xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4260 xmlNodeSetPtr newset = NULL;
4261
Daniel Veillard00fdf371999-10-08 09:40:39 +00004262 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004263 if ((CUR == '.') && (NXT(1) == '.')) {
4264 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004265 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004266 if (ctxt->context->nodelist == NULL) {
4267 STRANGE
4268 xmlXPathRoot(ctxt);
4269 }
4270 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4271 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4272 if (ctxt->context->nodelist != NULL)
4273 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4274 ctxt->context->nodelist = newset;
4275 ctxt->context->node = NULL;
4276 } else if (CUR == '.') {
4277 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004278 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004279 } else {
4280 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004281 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004282 while (CUR == '[') {
4283 xmlXPathEvalPredicate(ctxt);
4284 }
4285 }
4286#ifdef DEBUG_STEP
4287 fprintf(xmlXPathDebug, "Step : ");
4288 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4289#endif
4290}
4291
4292/**
4293 * xmlXPathEvalRelativeLocationPath:
4294 * @ctxt: the XPath Parser context
4295 *
4296 * [3] RelativeLocationPath ::= Step
4297 * | RelativeLocationPath '/' Step
4298 * | AbbreviatedRelativeLocationPath
4299 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4300 *
4301 */
4302void
4303xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4304 xmlNodeSetPtr newset = NULL;
4305
Daniel Veillard00fdf371999-10-08 09:40:39 +00004306 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004307 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004308 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004309 while (CUR == '/') {
4310 if ((CUR == '/') && (NXT(1) == '/')) {
4311 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004312 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004313 if (ctxt->context->nodelist == NULL) {
4314 STRANGE
4315 xmlXPathRoot(ctxt);
4316 }
4317 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4318 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4319 if (ctxt->context->nodelist != NULL)
4320 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4321 ctxt->context->nodelist = newset;
4322 ctxt->context->node = NULL;
4323 xmlXPathEvalStep(ctxt);
4324 } else if (CUR == '/') {
4325 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004326 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004327 xmlXPathEvalStep(ctxt);
4328 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004329 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004330 }
4331}
4332
4333/**
4334 * xmlXPathEvalLocationPath:
4335 * @ctxt: the XPath Parser context
4336 *
4337 * [1] LocationPath ::= RelativeLocationPath
4338 * | AbsoluteLocationPath
4339 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4340 * | AbbreviatedAbsoluteLocationPath
4341 * [10] AbbreviatedAbsoluteLocationPath ::=
4342 * '//' RelativeLocationPath
4343 *
4344 * // is short for /descendant-or-self::node()/. For example,
4345 * //para is short for /descendant-or-self::node()/child::para and
4346 * so will select any para element in the document (even a para element
4347 * that is a document element will be selected by //para since the
4348 * document element node is a child of the root node); div//para is
4349 * short for div/descendant-or-self::node()/child::para and so will
4350 * select all para descendants of div children.
4351 */
4352void
4353xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4354 xmlNodeSetPtr newset = NULL;
4355
Daniel Veillard00fdf371999-10-08 09:40:39 +00004356 SKIP_BLANKS;
4357 if (CUR != '/') {
4358 xmlXPathEvalRelativeLocationPath(ctxt);
4359 } else {
4360 while (CUR == '/') {
4361 if ((CUR == '/') && (NXT(1) == '/')) {
4362 SKIP(2);
4363 SKIP_BLANKS;
4364 if (ctxt->context->nodelist == NULL)
4365 xmlXPathRoot(ctxt);
4366 newset = xmlXPathNodeCollectAndTest(ctxt,
4367 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4368 XML_ELEMENT_NODE, NULL, NULL);
4369 if (ctxt->context->nodelist != NULL)
4370 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4371 ctxt->context->nodelist = newset;
4372 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004373 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004374 } else if (CUR == '/') {
4375 NEXT;
4376 SKIP_BLANKS;
4377 xmlXPathRoot(ctxt);
4378 if (CUR != 0)
4379 xmlXPathEvalRelativeLocationPath(ctxt);
4380 } else {
4381 xmlXPathEvalRelativeLocationPath(ctxt);
4382 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004383 }
4384 }
4385}
4386
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004387/**
4388 * xmlXPathEval:
4389 * @str: the XPath expression
4390 * @ctxt: the XPath context
4391 *
4392 * Evaluate the XPath Location Path in the given context.
4393 *
4394 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4395 * the caller has to free the object.
4396 */
4397xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004398xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004399 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004400 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004401
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004402 xmlXPathInit();
4403
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004404 CHECK_CONTEXT
4405
4406 if (xmlXPathDebug == NULL)
4407 xmlXPathDebug = stderr;
4408 pctxt = xmlXPathNewParserContext(str, ctxt);
4409 xmlXPathEvalLocationPath(pctxt);
4410
Daniel Veillardb96e6431999-08-29 21:02:19 +00004411 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004412 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004413 tmp = valuePop(pctxt);
4414 if (tmp != NULL);
4415 xmlXPathFreeObject(tmp);
4416 } while (tmp != NULL);
4417 if (res == NULL)
4418 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004419 xmlXPathFreeParserContext(pctxt);
4420 return(res);
4421}
4422
4423/**
4424 * xmlXPathEvalExpression:
4425 * @str: the XPath expression
4426 * @ctxt: the XPath context
4427 *
4428 * Evaluate the XPath expression in the given context.
4429 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004430 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004431 * the caller has to free the object.
4432 */
4433xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004434xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004435 xmlXPathParserContextPtr pctxt;
4436 xmlXPathObjectPtr res, tmp;
4437
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004438 xmlXPathInit();
4439
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004440 CHECK_CONTEXT
4441
4442 if (xmlXPathDebug == NULL)
4443 xmlXPathDebug = stderr;
4444 pctxt = xmlXPathNewParserContext(str, ctxt);
4445 xmlXPathEvalExpr(pctxt);
4446
4447 res = valuePop(pctxt);
4448 do {
4449 tmp = valuePop(pctxt);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004450 if (tmp != NULL);
4451 xmlXPathFreeObject(tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004452 } while (tmp != NULL);
4453 xmlXPathFreeParserContext(pctxt);
4454 return(res);
4455}
4456