blob: 9181e338c90e7f7fcce406bcf3978387d980eae1 [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer.
5 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
17#define HAVE_FCNTL_H
18#include <io.h>
19#else
20#include "config.h"
21#endif
22
23#include <stdio.h>
24#include <string.h>
25
26#ifdef HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000029#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000030#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000031#endif
32#ifdef HAVE_MATH_H
33#include <float.h>
34#endif
35#ifdef HAVE_IEEEFP_H
36#include <ieeefp.h>
37#endif
38#ifdef HAVE_NAN_H
39#include <nan.h>
40#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000041#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000042#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000043#endif
44
Daniel Veillard6454aec1999-09-02 22:04:43 +000045#include "xmlmemory.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000046#include "tree.h"
Daniel Veillardb96e6431999-08-29 21:02:19 +000047#include "valid.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000048#include "xpath.h"
49#include "parserInternals.h"
50
51/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000052 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000053 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000054 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000055double xmlXPathNAN = 0;
56double xmlXPathPINF = 1;
57double xmlXPathMINF = -1;
58
Daniel Veillardb05deb71999-08-10 19:04:08 +000059#ifndef isinf
60#ifndef HAVE_ISINF
61
62#if HAVE_FPCLASS
63
64int isinf(double d) {
65 fpclass_t type = fpclass(d);
66 switch (type) {
67 case FP_NINF:
68 return(-1);
69 case FP_PINF:
70 return(1);
71 default:
72 return(0);
73 }
74 return(0);
75}
76
77#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
78
79#if HAVE_FP_CLASS_H
80#include <fp_class.h>
81#endif
82
83int isinf(double d) {
84#if HAVE_FP_CLASS
85 int fpclass = fp_class(d);
86#else
87 int fpclass = fp_class_d(d);
88#endif
89 if (fpclass == FP_POS_INF)
90 return(1);
91 if (fpclass == FP_NEG_INF)
92 return(-1);
93 return(0);
94}
95
96#elif defined(HAVE_CLASS)
97
98int isinf(double d) {
99 int fpclass = class(d);
100 if (fpclass == FP_PLUS_INF)
101 return(1);
102 if (fpclass == FP_MINUS_INF)
103 return(-1);
104 return(0);
105}
106#elif defined(finite) || defined(HAVE_FINITE)
107int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000108#elif defined(HUGE_VAL)
109static int isinf(double x)
110{
111 if (x == HUGE_VAL)
112 return(1);
113 if (x == -HUGE_VAL)
114 return(-1);
115 return(0);
116}
117#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000118
119#endif /* ! HAVE_ISINF */
120#endif /* ! defined(isinf) */
121
122#ifndef isnan
123#ifndef HAVE_ISNAN
124
125#ifdef HAVE_ISNAND
126#define isnan(f) isnand(f)
127#endif /* HAVE_iSNAND */
128
129#endif /* ! HAVE_iSNAN */
130#endif /* ! defined(isnan) */
131
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000132/**
133 * xmlXPathInit:
134 *
135 * Initialize the XPath environment
136 */
137void
138xmlXPathInit(void) {
139 static int initialized = 0;
140
141 if (initialized) return;
142
143 xmlXPathNAN = 0;
144 xmlXPathNAN /= 0;
145
146 xmlXPathPINF = 1;
147 xmlXPathPINF /= 0;
148
149 xmlXPathMINF = -1;
150 xmlXPathMINF /= 0;
151
152 initialized = 1;
153}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000154
155/* #define DEBUG */
156/* #define DEBUG_STEP */
157/* #define DEBUG_EXPR */
158
159FILE *xmlXPathDebug = NULL;
160
161#define TODO \
162 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
163 __FILE__, __LINE__);
164
165#define STRANGE \
166 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
167 __FILE__, __LINE__);
168
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000169double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000170void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000171
172/************************************************************************
173 * *
174 * Parser stacks related functions and macros *
175 * *
176 ************************************************************************/
177
178/*
179 * Generic function for accessing stacks in the Parser Context
180 */
181
182#define PUSH_AND_POP(type, name) \
183extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
184 if (ctxt->name##Nr >= ctxt->name##Max) { \
185 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000186 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000187 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
188 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000189 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000190 exit(1); \
191 } \
192 } \
193 ctxt->name##Tab[ctxt->name##Nr] = value; \
194 ctxt->name = value; \
195 return(ctxt->name##Nr++); \
196} \
197extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
198 type ret; \
199 if (ctxt->name##Nr <= 0) return(0); \
200 ctxt->name##Nr--; \
201 if (ctxt->name##Nr > 0) \
202 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
203 else \
204 ctxt->name = NULL; \
205 ret = ctxt->name##Tab[ctxt->name##Nr]; \
206 ctxt->name##Tab[ctxt->name##Nr] = 0; \
207 return(ret); \
208} \
209
210PUSH_AND_POP(xmlXPathObjectPtr, value)
211
212/*
213 * Macros for accessing the content. Those should be used only by the parser,
214 * and not exported.
215 *
216 * Dirty macros, i.e. one need to make assumption on the context to use them
217 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000218 * CUR_PTR return the current pointer to the xmlChar to be parsed.
219 * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000220 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
221 * in UNICODE mode. This should be used internally by the parser
222 * only to compare to ASCII values otherwise it would break when
223 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000224 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000225 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000226 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000227 * strings within the parser.
228 * CURRENT Returns the current char value, with the full decoding of
229 * UTF-8 if we are using this mode. It returns an int.
230 * NEXT Skip to the next character, this does the proper decoding
231 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000232 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000233 */
234
235#define CUR (*ctxt->cur)
236#define SKIP(val) ctxt->cur += (val)
237#define NXT(val) ctxt->cur[(val)]
238#define CUR_PTR ctxt->cur
239
240#define SKIP_BLANKS \
241 while (IS_BLANK(*(ctxt->cur))) NEXT
242
243#ifndef USE_UTF_8
244#define CURRENT (*ctxt->cur)
245#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
246#else
247#endif
248
249/************************************************************************
250 * *
251 * Error handling routines *
252 * *
253 ************************************************************************/
254
255#define XPATH_EXPRESSION_OK 0
256#define XPATH_NUMBER_ERROR 1
257#define XPATH_UNFINISHED_LITERAL_ERROR 2
258#define XPATH_START_LITERAL_ERROR 3
259#define XPATH_VARIABLE_REF_ERROR 4
260#define XPATH_UNDEF_VARIABLE_ERROR 5
261#define XPATH_INVALID_PREDICATE_ERROR 6
262#define XPATH_EXPR_ERROR 7
263#define XPATH_UNCLOSED_ERROR 8
264#define XPATH_UNKNOWN_FUNC_ERROR 9
265#define XPATH_INVALID_OPERAND 10
266#define XPATH_INVALID_TYPE 11
267#define XPATH_INVALID_ARITY 12
268
269const char *xmlXPathErrorMessages[] = {
270 "Ok",
271 "Number encoding",
272 "Unfinished litteral",
273 "Start of litteral",
274 "Expected $ for variable reference",
275 "Undefined variable",
276 "Invalid predicate",
277 "Invalid expression",
278 "Missing closing curly brace",
279 "Unregistered function",
280 "Invalid operand",
281 "Invalid type",
282 "Invalid number of arguments",
283};
284
285/**
286 * xmlXPathError:
287 * @ctxt: the XPath Parser context
288 * @file: the file name
289 * @line: the line number
290 * @no: the error number
291 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000292 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000293 *
294 * Returns the newly created object.
295 */
296void
297xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
298 int line, int no) {
299 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000300 const xmlChar *cur;
301 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000302
303 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
304 xmlXPathErrorMessages[no]);
305
306 cur = ctxt->cur;
307 base = ctxt->base;
308 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
309 cur--;
310 }
311 n = 0;
312 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
313 cur--;
314 if ((*cur == '\n') || (*cur == '\r')) cur++;
315 base = cur;
316 n = 0;
317 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
318 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
319 n++;
320 }
321 fprintf(xmlXPathDebug, "\n");
322 cur = ctxt->cur;
323 while ((*cur == '\n') || (*cur == '\r'))
324 cur--;
325 n = 0;
326 while ((cur != base) && (n++ < 80)) {
327 fprintf(xmlXPathDebug, " ");
328 base++;
329 }
330 fprintf(xmlXPathDebug,"^\n");
331}
332
333#define CHECK_ERROR \
334 if (ctxt->error != XPATH_EXPRESSION_OK) return
335
336#define ERROR(X) \
337 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
338 ctxt->error = (X); return; }
339
Daniel Veillard991e63d1999-08-15 23:32:28 +0000340#define ERROR0(X) \
341 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
342 ctxt->error = (X); return(0); }
343
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000344#define CHECK_TYPE(typeval) \
345 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
346 ERROR(XPATH_INVALID_TYPE) \
347
348
349/************************************************************************
350 * *
351 * Routines to handle NodeSets *
352 * *
353 ************************************************************************/
354
355#define XML_NODESET_DEFAULT 10
356/**
357 * xmlXPathNodeSetCreate:
358 * @val: an initial xmlNodePtr, or NULL
359 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000360 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000361 *
362 * Returns the newly created object.
363 */
364xmlNodeSetPtr
365xmlXPathNodeSetCreate(xmlNodePtr val) {
366 xmlNodeSetPtr ret;
367
Daniel Veillard6454aec1999-09-02 22:04:43 +0000368 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000369 if (ret == NULL) {
370 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
371 return(NULL);
372 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000373 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000374 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000375 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000376 sizeof(xmlNodePtr));
377 if (ret->nodeTab == NULL) {
378 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
379 return(NULL);
380 }
381 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000382 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000383 ret->nodeMax = XML_NODESET_DEFAULT;
384 ret->nodeTab[ret->nodeNr++] = val;
385 }
386 return(ret);
387}
388
389/**
390 * xmlXPathNodeSetAdd:
391 * @cur: the initial node set
392 * @val: a new xmlNodePtr
393 *
394 * add a new xmlNodePtr ot an existing NodeSet
395 */
396void
397xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
398 int i;
399
400 if (val == NULL) return;
401
402 /*
403 * check against doublons
404 */
405 for (i = 0;i < cur->nodeNr;i++)
406 if (cur->nodeTab[i] == val) return;
407
408 /*
409 * grow the nodeTab if needed
410 */
411 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000412 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000413 sizeof(xmlNodePtr));
414 if (cur->nodeTab == NULL) {
415 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
416 return;
417 }
418 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000419 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000420 cur->nodeMax = XML_NODESET_DEFAULT;
421 } else if (cur->nodeNr == cur->nodeMax) {
422 xmlNodePtr *temp;
423
424 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000425 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000426 sizeof(xmlNodePtr));
427 if (temp == NULL) {
428 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
429 return;
430 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000431 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000432 }
433 cur->nodeTab[cur->nodeNr++] = val;
434}
435
436/**
437 * xmlXPathNodeSetMerge:
438 * @val1: the first NodeSet
439 * @val2: the second NodeSet
440 *
441 * Merges two nodesets, all nodes from @val2 are added to @val1
442 *
443 * Returns val1 once extended or NULL in case of error.
444 */
445xmlNodeSetPtr
446xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
447 int i;
448
449 if (val1 == NULL) return(NULL);
450 if (val2 == NULL) return(val1);
451
452 /*
453 * !!!!! this can be optimized a lot, knowing that both
454 * val1 and val2 already have unicity of their values.
455 */
456
457 for (i = 0;i < val2->nodeNr;i++)
458 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
459
460 return(val1);
461}
462
463/**
464 * xmlXPathNodeSetDel:
465 * @cur: the initial node set
466 * @val: an xmlNodePtr
467 *
468 * Removes an xmlNodePtr from an existing NodeSet
469 */
470void
471xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
472 int i;
473
474 if (cur == NULL) return;
475 if (val == NULL) return;
476
477 /*
478 * check against doublons
479 */
480 for (i = 0;i < cur->nodeNr;i++)
481 if (cur->nodeTab[i] == val) break;
482
483 if (i >= cur->nodeNr) {
484#ifdef DEBUG
485 fprintf(xmlXPathDebug,
486 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
487 val->name);
488#endif
489 return;
490 }
491 cur->nodeNr--;
492 for (;i < cur->nodeNr;i++)
493 cur->nodeTab[i] = cur->nodeTab[i + 1];
494 cur->nodeTab[cur->nodeNr] = NULL;
495}
496
497/**
498 * xmlXPathNodeSetRemove:
499 * @cur: the initial node set
500 * @val: the index to remove
501 *
502 * Removes an entry from an existing NodeSet list.
503 */
504void
505xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
506 if (cur == NULL) return;
507 if (val >= cur->nodeNr) return;
508 cur->nodeNr--;
509 for (;val < cur->nodeNr;val++)
510 cur->nodeTab[val] = cur->nodeTab[val + 1];
511 cur->nodeTab[cur->nodeNr] = NULL;
512}
513
514/**
515 * xmlXPathFreeNodeSet:
516 * @obj: the xmlNodeSetPtr to free
517 *
518 * Free the NodeSet compound (not the actual nodes !).
519 */
520void
521xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
522 if (obj == NULL) return;
523 if (obj->nodeTab != NULL) {
524#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000525 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000526#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000527 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000528 }
529#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000530 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000531#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000532 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000533}
534
Daniel Veillardb96e6431999-08-29 21:02:19 +0000535#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000536/**
537 * xmlXPathDebugNodeSet:
538 * @output: a FILE * for the output
539 * @obj: the xmlNodeSetPtr to free
540 *
541 * Quick display of a NodeSet
542 */
543void
544xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
545 int i;
546
547 if (output == NULL) output = xmlXPathDebug;
548 if (obj == NULL) {
549 fprintf(output, "NodeSet == NULL !\n");
550 return;
551 }
552 if (obj->nodeNr == 0) {
553 fprintf(output, "NodeSet is empty\n");
554 return;
555 }
556 if (obj->nodeTab == NULL) {
557 fprintf(output, " nodeTab == NULL !\n");
558 return;
559 }
560 for (i = 0; i < obj->nodeNr; i++) {
561 if (obj->nodeTab[i] == NULL) {
562 fprintf(output, " NULL !\n");
563 return;
564 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000565 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
566 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000567 fprintf(output, " /");
568 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000569 fprintf(output, " noname!");
570 else fprintf(output, " %s", obj->nodeTab[i]->name);
571 }
572 fprintf(output, "\n");
573}
574#endif
575
576/************************************************************************
577 * *
578 * Routines to handle Variable *
579 * *
580 * UNIMPLEMENTED CURRENTLY *
581 * *
582 ************************************************************************/
583
584/**
585 * xmlXPathVariablelookup:
586 * @ctxt: the XPath Parser context
587 * @prefix: the variable name namespace if any
588 * @name: the variable name
589 *
590 * Search in the Variable array of the context for the given
591 * variable value.
592 *
593 * UNIMPLEMENTED: always return NULL.
594 *
595 * Returns the value or NULL if not found
596 */
597xmlXPathObjectPtr
598xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000599 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000600 return(NULL);
601}
602
603/************************************************************************
604 * *
605 * Routines to handle Values *
606 * *
607 ************************************************************************/
608
609/* Allocations are terrible, one need to optimize all this !!! */
610
611/**
612 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000613 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000614 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000615 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000616 *
617 * Returns the newly created object.
618 */
619xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000620xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000621 xmlXPathObjectPtr ret;
622
Daniel Veillard6454aec1999-09-02 22:04:43 +0000623 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000624 if (ret == NULL) {
625 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
626 return(NULL);
627 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000628 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000629 ret->type = XPATH_NUMBER;
630 ret->floatval = val;
631 return(ret);
632}
633
634/**
635 * xmlXPathNewBoolean:
636 * @val: the boolean value
637 *
638 * Create a new xmlXPathObjectPtr of type boolean and of value @val
639 *
640 * Returns the newly created object.
641 */
642xmlXPathObjectPtr
643xmlXPathNewBoolean(int val) {
644 xmlXPathObjectPtr ret;
645
Daniel Veillard6454aec1999-09-02 22:04:43 +0000646 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000647 if (ret == NULL) {
648 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
649 return(NULL);
650 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000651 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000652 ret->type = XPATH_BOOLEAN;
653 ret->boolval = (val != 0);
654 return(ret);
655}
656
657/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000658 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000659 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000660 *
661 * Create a new xmlXPathObjectPtr of type string and of value @val
662 *
663 * Returns the newly created object.
664 */
665xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000666xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000667 xmlXPathObjectPtr ret;
668
Daniel Veillard6454aec1999-09-02 22:04:43 +0000669 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000670 if (ret == NULL) {
671 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
672 return(NULL);
673 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000674 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000675 ret->type = XPATH_STRING;
676 ret->stringval = xmlStrdup(val);
677 return(ret);
678}
679
680/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000681 * xmlXPathNewCString:
682 * @val: the char * value
683 *
684 * Create a new xmlXPathObjectPtr of type string and of value @val
685 *
686 * Returns the newly created object.
687 */
688xmlXPathObjectPtr
689xmlXPathNewCString(const char *val) {
690 xmlXPathObjectPtr ret;
691
Daniel Veillard6454aec1999-09-02 22:04:43 +0000692 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000693 if (ret == NULL) {
694 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
695 return(NULL);
696 }
697 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
698 ret->type = XPATH_STRING;
699 ret->stringval = xmlStrdup(BAD_CAST val);
700 return(ret);
701}
702
703/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000704 * xmlXPathNewNodeSet:
705 * @val: the NodePtr value
706 *
707 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
708 * it with the single Node @val
709 *
710 * Returns the newly created object.
711 */
712xmlXPathObjectPtr
713xmlXPathNewNodeSet(xmlNodePtr val) {
714 xmlXPathObjectPtr ret;
715
Daniel Veillard6454aec1999-09-02 22:04:43 +0000716 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000717 if (ret == NULL) {
718 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
719 return(NULL);
720 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000721 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000722 ret->type = XPATH_NODESET;
723 ret->nodesetval = xmlXPathNodeSetCreate(val);
724 return(ret);
725}
726
727/**
728 * xmlXPathNewNodeSetList:
729 * @val: an existing NodeSet
730 *
731 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
732 * it with the Nodeset @val
733 *
734 * Returns the newly created object.
735 */
736xmlXPathObjectPtr
737xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
738 xmlXPathObjectPtr ret;
739
Daniel Veillard6454aec1999-09-02 22:04:43 +0000740 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000741 if (ret == NULL) {
742 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
743 return(NULL);
744 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000745 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000746 ret->type = XPATH_NODESET;
747 ret->nodesetval = val;
748 return(ret);
749}
750
751/**
752 * xmlXPathFreeObject:
753 * @obj: the object to free
754 *
755 * Free up an xmlXPathObjectPtr object.
756 */
757void
758xmlXPathFreeObject(xmlXPathObjectPtr obj) {
759 if (obj == NULL) return;
760 if (obj->nodesetval != NULL)
761 xmlXPathFreeNodeSet(obj->nodesetval);
762 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000763 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000764#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000765 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000766#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000767 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000768}
769
770/************************************************************************
771 * *
772 * Routines to handle XPath contexts *
773 * *
774 ************************************************************************/
775
776/**
777 * xmlXPathNewContext:
778 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000779 *
780 * Create a new xmlXPathContext
781 *
782 * Returns the xmlXPathContext just allocated.
783 */
784xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000785xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000786 xmlXPathContextPtr ret;
787
Daniel Veillard6454aec1999-09-02 22:04:43 +0000788 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000789 if (ret == NULL) {
790 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
791 return(NULL);
792 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000793 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000794 ret->doc = doc;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000795
796 ret->nb_variables = 0;
797 ret->max_variables = 0;
798 ret->variables = NULL;
799
800 ret->nb_types = 0;
801 ret->max_types = 0;
802 ret->types = NULL;
803
804 ret->nb_funcs = 0;
805 ret->max_funcs = 0;
806 ret->funcs = NULL;
807
808 ret->nb_axis = 0;
809 ret->max_axis = 0;
810 ret->axis = NULL;
811
Daniel Veillardb96e6431999-08-29 21:02:19 +0000812 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000813 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000814 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000815 return(ret);
816}
817
818/**
819 * xmlXPathFreeContext:
820 * @ctxt: the context to free
821 *
822 * Free up an xmlXPathContext
823 */
824void
825xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000826 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000827 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000828
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000829#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000830 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000831#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000832 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000833}
834
835/************************************************************************
836 * *
837 * Routines to handle XPath parser contexts *
838 * *
839 ************************************************************************/
840
841#define CHECK_CTXT \
842 if (ctxt == NULL) { \
843 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
844 __FILE__, __LINE__); \
845 } \
846
847
848#define CHECK_CONTEXT \
849 if (ctxt == NULL) { \
850 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
851 __FILE__, __LINE__); \
852 } \
853 if (ctxt->doc == NULL) { \
854 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
855 __FILE__, __LINE__); \
856 } \
857 if (ctxt->doc->root == NULL) { \
858 fprintf(xmlXPathDebug, \
859 "%s:%d Internal error: document without root\n", \
860 __FILE__, __LINE__); \
861 } \
862
863
864/**
865 * xmlXPathNewParserContext:
866 * @str: the XPath expression
867 * @ctxt: the XPath context
868 *
869 * Create a new xmlXPathParserContext
870 *
871 * Returns the xmlXPathParserContext just allocated.
872 */
873xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000874xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000875 xmlXPathParserContextPtr ret;
876
Daniel Veillard6454aec1999-09-02 22:04:43 +0000877 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000878 if (ret == NULL) {
879 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
880 return(NULL);
881 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000882 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000883 ret->cur = ret->base = str;
884 ret->context = ctxt;
885
886 /* Allocate the value stack */
887 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000888 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000889 ret->valueNr = 0;
890 ret->valueMax = 10;
891 ret->value = NULL;
892 return(ret);
893}
894
895/**
896 * xmlXPathFreeParserContext:
897 * @ctxt: the context to free
898 *
899 * Free up an xmlXPathParserContext
900 */
901void
902xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
903 if (ctxt->valueTab != NULL) {
904#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000905 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000906#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000907 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000908 }
909#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000910 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000911#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000912 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000913}
914
915/************************************************************************
916 * *
917 * The implicit core function library *
918 * *
919 ************************************************************************/
920
921/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000922 * Auto-pop and cast to a number
923 */
924void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
925
926#define CHECK_ARITY(x) \
927 if (nargs != (x)) { \
928 ERROR(XPATH_INVALID_ARITY); \
929 } \
930
931
932#define POP_FLOAT \
933 arg = valuePop(ctxt); \
934 if (arg == NULL) { \
935 ERROR(XPATH_INVALID_OPERAND); \
936 } \
937 if (arg->type != XPATH_NUMBER) { \
938 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000939 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000940 arg = valuePop(ctxt); \
941 }
942
943/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000944 * xmlXPathEqualNodeSetString
945 * @arg: the nodeset object argument
946 * @str: the string to compare to.
947 *
948 * Implement the equal operation on XPath objects content: @arg1 == @arg2
949 * If one object to be compared is a node-set and the other is a string,
950 * then the comparison will be true if and only if there is a node in
951 * the node-set such that the result of performing the comparison on the
952 * string-value of the node and the other string is true.
953 *
954 * Returns 0 or 1 depending on the results of the test.
955 */
956int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000957xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000958 int i;
959 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000960 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000961
962 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
963 return(0);
964 ns = arg->nodesetval;
965 for (i = 0;i < ns->nodeNr;i++) {
966 str2 = xmlNodeGetContent(ns->nodeTab[i]);
967 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000968 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000969 return(1);
970 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000971 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000972 }
973 return(0);
974}
975
976/**
977 * xmlXPathEqualNodeSetFloat
978 * @arg: the nodeset object argument
979 * @f: the float to compare to
980 *
981 * Implement the equal operation on XPath objects content: @arg1 == @arg2
982 * If one object to be compared is a node-set and the other is a number,
983 * then the comparison will be true if and only if there is a node in
984 * the node-set such that the result of performing the comparison on the
985 * number to be compared and on the result of converting the string-value
986 * of that node to a number using the number function is true.
987 *
988 * Returns 0 or 1 depending on the results of the test.
989 */
990int
991xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000992 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +0000993
994 if ((arg == NULL) || (arg->type != XPATH_NODESET))
995 return(0);
996
997 if (isnan(f))
998 sprintf(buf, "NaN");
999 else if (isinf(f) > 0)
1000 sprintf(buf, "+Infinity");
1001 else if (isinf(f) < 0)
1002 sprintf(buf, "-Infinity");
1003 else
1004 sprintf(buf, "%0g", f);
1005
Daniel Veillardb96e6431999-08-29 21:02:19 +00001006 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001007}
1008
1009
1010/**
1011 * xmlXPathEqualNodeSets
1012 * @arg1: first nodeset object argument
1013 * @arg2: second nodeset object argument
1014 *
1015 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1016 * If both objects to be compared are node-sets, then the comparison
1017 * will be true if and only if there is a node in the first node-set and
1018 * a node in the second node-set such that the result of performing the
1019 * comparison on the string-values of the two nodes is true.
1020 *
1021 * (needless to say, this is a costly operation)
1022 *
1023 * Returns 0 or 1 depending on the results of the test.
1024 */
1025int
1026xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1027 int i;
1028 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001029 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001030
1031 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1032 return(0);
1033 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1034 return(0);
1035
1036 ns = arg1->nodesetval;
1037 for (i = 0;i < ns->nodeNr;i++) {
1038 str = xmlNodeGetContent(ns->nodeTab[i]);
1039 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001040 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001041 return(1);
1042 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001043 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001044 }
1045 return(0);
1046}
1047
1048/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001049 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001050 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001051 *
1052 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1053 *
1054 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001055 */
1056int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001057xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1058 xmlXPathObjectPtr arg1, arg2;
1059 int ret = 0;
1060
1061 arg1 = valuePop(ctxt);
1062 if (arg1 == NULL)
1063 ERROR0(XPATH_INVALID_OPERAND);
1064
1065 arg2 = valuePop(ctxt);
1066 if (arg2 == NULL) {
1067 xmlXPathFreeObject(arg1);
1068 ERROR0(XPATH_INVALID_OPERAND);
1069 }
1070
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001071 if (arg1 == arg2) {
1072#ifdef DEBUG_EXPR
1073 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1074#endif
1075 return(1);
1076 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001077
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001078 switch (arg1->type) {
1079 case XPATH_UNDEFINED:
1080#ifdef DEBUG_EXPR
1081 fprintf(xmlXPathDebug, "Equal: undefined\n");
1082#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001083 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001084 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001085 switch (arg2->type) {
1086 case XPATH_UNDEFINED:
1087#ifdef DEBUG_EXPR
1088 fprintf(xmlXPathDebug, "Equal: undefined\n");
1089#endif
1090 break;
1091 case XPATH_NODESET:
1092 ret = xmlXPathEqualNodeSets(arg1, arg2);
1093 break;
1094 case XPATH_BOOLEAN:
1095 if ((arg1->nodesetval == NULL) ||
1096 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1097 else
1098 ret = 1;
1099 ret = (ret == arg2->boolval);
1100 break;
1101 case XPATH_NUMBER:
1102 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1103 break;
1104 case XPATH_STRING:
1105 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1106 break;
1107 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001108 break;
1109 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001110 switch (arg2->type) {
1111 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001112#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001113 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001114#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001115 break;
1116 case XPATH_NODESET:
1117 if ((arg2->nodesetval == NULL) ||
1118 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1119 else
1120 ret = 1;
1121 break;
1122 case XPATH_BOOLEAN:
1123#ifdef DEBUG_EXPR
1124 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1125 arg1->boolval, arg2->boolval);
1126#endif
1127 ret = (arg1->boolval == arg2->boolval);
1128 break;
1129 case XPATH_NUMBER:
1130 if (arg2->floatval) ret = 1;
1131 else ret = 0;
1132 ret = (arg1->boolval == ret);
1133 break;
1134 case XPATH_STRING:
1135 if ((arg2->stringval == NULL) ||
1136 (arg2->stringval[0] == 0)) ret = 0;
1137 else
1138 ret = 1;
1139 ret = (arg1->boolval == ret);
1140 break;
1141 }
1142 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001143 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001144 switch (arg2->type) {
1145 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001146#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001147 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001148#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001149 break;
1150 case XPATH_NODESET:
1151 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1152 break;
1153 case XPATH_BOOLEAN:
1154 if (arg1->floatval) ret = 1;
1155 else ret = 0;
1156 ret = (arg2->boolval == ret);
1157 break;
1158 case XPATH_STRING:
1159 valuePush(ctxt, arg2);
1160 xmlXPathNumberFunction(ctxt, 1);
1161 arg2 = valuePop(ctxt);
1162 /* no break on purpose */
1163 case XPATH_NUMBER:
1164 ret = (arg1->floatval == arg2->floatval);
1165 break;
1166 }
1167 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001168 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001169 switch (arg2->type) {
1170 case XPATH_UNDEFINED:
1171#ifdef DEBUG_EXPR
1172 fprintf(xmlXPathDebug, "Equal: undefined\n");
1173#endif
1174 break;
1175 case XPATH_NODESET:
1176 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1177 break;
1178 case XPATH_BOOLEAN:
1179 if ((arg1->stringval == NULL) ||
1180 (arg1->stringval[0] == 0)) ret = 0;
1181 else
1182 ret = 1;
1183 ret = (arg2->boolval == ret);
1184 break;
1185 case XPATH_STRING:
1186 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1187 break;
1188 case XPATH_NUMBER:
1189 valuePush(ctxt, arg1);
1190 xmlXPathNumberFunction(ctxt, 1);
1191 arg1 = valuePop(ctxt);
1192 ret = (arg1->floatval == arg2->floatval);
1193 break;
1194 }
1195 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001196#ifdef DEBUG_EXPR
1197 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
1198 arg1->stringval, arg2->stringval);
1199#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001200 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001201 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001202 xmlXPathFreeObject(arg1);
1203 xmlXPathFreeObject(arg2);
1204 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001205}
1206
1207/**
1208 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001209 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001210 * @inf: less than (1) or greater than (2)
1211 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001212 *
1213 * Implement the compare operation on XPath objects:
1214 * @arg1 < @arg2 (1, 1, ...
1215 * @arg1 <= @arg2 (1, 0, ...
1216 * @arg1 > @arg2 (0, 1, ...
1217 * @arg1 >= @arg2 (0, 0, ...
1218 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001219 * When neither object to be compared is a node-set and the operator is
1220 * <=, <, >=, >, then the objects are compared by converted both objects
1221 * to numbers and comparing the numbers according to IEEE 754. The <
1222 * comparison will be true if and only if the first number is less than the
1223 * second number. The <= comparison will be true if and only if the first
1224 * number is less than or equal to the second number. The > comparison
1225 * will be true if and only if the first number is greater than the second
1226 * number. The >= comparison will be true if and only if the first number
1227 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001228 */
1229int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001230xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1231 int ret = 0;
1232 xmlXPathObjectPtr arg1, arg2;
1233
1234 arg2 = valuePop(ctxt);
1235 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1236 if (arg2 != NULL)
1237 xmlXPathFreeObject(arg2);
1238 ERROR0(XPATH_INVALID_OPERAND);
1239 }
1240
1241 arg1 = valuePop(ctxt);
1242 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1243 if (arg1 != NULL)
1244 xmlXPathFreeObject(arg1);
1245 xmlXPathFreeObject(arg2);
1246 ERROR0(XPATH_INVALID_OPERAND);
1247 }
1248
1249 if (arg1->type != XPATH_NUMBER) {
1250 valuePush(ctxt, arg1);
1251 xmlXPathNumberFunction(ctxt, 1);
1252 arg1 = valuePop(ctxt);
1253 }
1254 if (arg1->type != XPATH_NUMBER) {
1255 xmlXPathFreeObject(arg1);
1256 xmlXPathFreeObject(arg2);
1257 ERROR0(XPATH_INVALID_OPERAND);
1258 }
1259 if (arg2->type != XPATH_NUMBER) {
1260 valuePush(ctxt, arg2);
1261 xmlXPathNumberFunction(ctxt, 1);
1262 arg2 = valuePop(ctxt);
1263 }
1264 if (arg2->type != XPATH_NUMBER) {
1265 xmlXPathFreeObject(arg1);
1266 xmlXPathFreeObject(arg2);
1267 ERROR0(XPATH_INVALID_OPERAND);
1268 }
1269 /*
1270 * Add tests for infinity and nan
1271 * => feedback on 3.4 for Inf and NaN
1272 */
1273 if (inf && strict)
1274 ret = (arg1->floatval < arg2->floatval);
1275 else if (inf && !strict)
1276 ret = (arg1->floatval <= arg2->floatval);
1277 else if (!inf && strict)
1278 ret = (arg1->floatval > arg2->floatval);
1279 else if (!inf && !strict)
1280 ret = (arg1->floatval >= arg2->floatval);
1281 xmlXPathFreeObject(arg1);
1282 xmlXPathFreeObject(arg2);
1283 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001284}
1285
1286/**
1287 * xmlXPathValueFlipSign:
1288 * @ctxt: the XPath Parser context
1289 *
1290 * Implement the unary - operation on an XPath object
1291 * The numeric operators convert their operands to numbers as if
1292 * by calling the number function.
1293 */
1294void
1295xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1296 xmlXPathObjectPtr arg;
1297
1298 POP_FLOAT
1299 arg->floatval = -arg->floatval;
1300 valuePush(ctxt, arg);
1301}
1302
1303/**
1304 * xmlXPathAddValues:
1305 * @ctxt: the XPath Parser context
1306 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001307 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001308 * The numeric operators convert their operands to numbers as if
1309 * by calling the number function.
1310 */
1311void
1312xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1313 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001314 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001315
1316 POP_FLOAT
1317 val = arg->floatval;
1318 xmlXPathFreeObject(arg);
1319
1320 POP_FLOAT
1321 arg->floatval += val;
1322 valuePush(ctxt, arg);
1323}
1324
1325/**
1326 * xmlXPathSubValues:
1327 * @ctxt: the XPath Parser context
1328 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001329 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001330 * The numeric operators convert their operands to numbers as if
1331 * by calling the number function.
1332 */
1333void
1334xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1335 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001336 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001337
1338 POP_FLOAT
1339 val = arg->floatval;
1340 xmlXPathFreeObject(arg);
1341
1342 POP_FLOAT
1343 arg->floatval -= val;
1344 valuePush(ctxt, arg);
1345}
1346
1347/**
1348 * xmlXPathMultValues:
1349 * @ctxt: the XPath Parser context
1350 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001351 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001352 * The numeric operators convert their operands to numbers as if
1353 * by calling the number function.
1354 */
1355void
1356xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1357 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001358 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001359
1360 POP_FLOAT
1361 val = arg->floatval;
1362 xmlXPathFreeObject(arg);
1363
1364 POP_FLOAT
1365 arg->floatval *= val;
1366 valuePush(ctxt, arg);
1367}
1368
1369/**
1370 * xmlXPathDivValues:
1371 * @ctxt: the XPath Parser context
1372 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001373 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001374 * The numeric operators convert their operands to numbers as if
1375 * by calling the number function.
1376 */
1377void
1378xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1379 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001380 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001381
1382 POP_FLOAT
1383 val = arg->floatval;
1384 xmlXPathFreeObject(arg);
1385
1386 POP_FLOAT
1387 arg->floatval /= val;
1388 valuePush(ctxt, arg);
1389}
1390
1391/**
1392 * xmlXPathModValues:
1393 * @ctxt: the XPath Parser context
1394 *
1395 * Implement the div operation on XPath objects: @arg1 / @arg2
1396 * The numeric operators convert their operands to numbers as if
1397 * by calling the number function.
1398 */
1399void
1400xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1401 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001402 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001403
1404 POP_FLOAT
1405 val = arg->floatval;
1406 xmlXPathFreeObject(arg);
1407
1408 POP_FLOAT
1409 arg->floatval /= val;
1410 valuePush(ctxt, arg);
1411}
1412
1413/************************************************************************
1414 * *
1415 * The traversal functions *
1416 * *
1417 ************************************************************************/
1418
1419#define AXIS_ANCESTOR 1
1420#define AXIS_ANCESTOR_OR_SELF 2
1421#define AXIS_ATTRIBUTE 3
1422#define AXIS_CHILD 4
1423#define AXIS_DESCENDANT 5
1424#define AXIS_DESCENDANT_OR_SELF 6
1425#define AXIS_FOLLOWING 7
1426#define AXIS_FOLLOWING_SIBLING 8
1427#define AXIS_NAMESPACE 9
1428#define AXIS_PARENT 10
1429#define AXIS_PRECEDING 11
1430#define AXIS_PRECEDING_SIBLING 12
1431#define AXIS_SELF 13
1432
1433/*
1434 * A traversal function enumerates nodes along an axis.
1435 * Initially it must be called with NULL, and it indicates
1436 * termination on the axis by returning NULL.
1437 */
1438typedef xmlNodePtr (*xmlXPathTraversalFunction)
1439 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1440
1441/**
1442 * mlXPathNextSelf:
1443 * @ctxt: the XPath Parser context
1444 * @cur: the current node in the traversal
1445 *
1446 * Traversal function for the "self" direction
1447 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001448 *
1449 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001450 */
1451xmlNodePtr
1452xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1453 if (cur == NULL)
1454 return(ctxt->context->node);
1455 return(NULL);
1456}
1457
1458/**
1459 * mlXPathNextChild:
1460 * @ctxt: the XPath Parser context
1461 * @cur: the current node in the traversal
1462 *
1463 * Traversal function for the "child" direction
1464 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001465 *
1466 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001467 */
1468xmlNodePtr
1469xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001470 if (cur == NULL) {
1471 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1472 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001473 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001474 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +00001475 if ((ctxt->context->node->type == XML_DOCUMENT_NODE) ||
1476 (ctxt->context->node->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001477 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001478 return(cur->next);
1479}
1480
1481/**
1482 * mlXPathNextDescendant:
1483 * @ctxt: the XPath Parser context
1484 * @cur: the current node in the traversal
1485 *
1486 * Traversal function for the "descendant" direction
1487 * the descendant axis contains the descendants of the context node in document
1488 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001489 *
1490 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001491 */
1492xmlNodePtr
1493xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001494 if (cur == NULL) {
1495 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1496 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001497 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001498 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001499
1500 if (cur->childs != NULL) return(cur->childs);
1501 if (cur->next != NULL) return(cur->next);
1502
1503 do {
1504 cur = cur->parent;
1505 if (cur == NULL) return(NULL);
1506 if (cur == ctxt->context->node) return(NULL);
1507 if (cur->next != NULL) {
1508 cur = cur->next;
1509 return(cur);
1510 }
1511 } while (cur != NULL);
1512 return(cur);
1513}
1514
1515/**
1516 * mlXPathNextDescendantOrSelf:
1517 * @ctxt: the XPath Parser context
1518 * @cur: the current node in the traversal
1519 *
1520 * Traversal function for the "descendant-or-self" direction
1521 * the descendant-or-self axis contains the context node and the descendants
1522 * of the context node in document order; thus the context node is the first
1523 * node on the axis, and the first child of the context node is the second node
1524 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001525 *
1526 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001527 */
1528xmlNodePtr
1529xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1530 if (cur == NULL)
1531 return(ctxt->context->node);
1532
Daniel Veillardb05deb71999-08-10 19:04:08 +00001533 if (cur == (xmlNodePtr) ctxt->context->doc)
1534 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001535 if (cur->childs != NULL) return(cur->childs);
1536 if (cur->next != NULL) return(cur->next);
1537
1538 do {
1539 cur = cur->parent;
1540 if (cur == NULL) return(NULL);
1541 if (cur == ctxt->context->node) return(NULL);
1542 if (cur->next != NULL) {
1543 cur = cur->next;
1544 return(cur);
1545 }
1546 } while (cur != NULL);
1547 return(cur);
1548}
1549
1550/**
1551 * xmlXPathNextParent:
1552 * @ctxt: the XPath Parser context
1553 * @cur: the current node in the traversal
1554 *
1555 * Traversal function for the "parent" direction
1556 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001557 *
1558 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001559 */
1560xmlNodePtr
1561xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1562 /*
1563 * !!!!!!!!!!!!!
1564 * the parent of an attribute or namespace node is the element
1565 * to which the attribute or namespace node is attached
1566 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001567 if (cur == NULL) {
1568 if (ctxt->context->node->parent == NULL)
1569 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001570 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001571 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001572 return(NULL);
1573}
1574
1575/**
1576 * xmlXPathNextAncestor:
1577 * @ctxt: the XPath Parser context
1578 * @cur: the current node in the traversal
1579 *
1580 * Traversal function for the "ancestor" direction
1581 * the ancestor axis contains the ancestors of the context node; the ancestors
1582 * of the context node consist of the parent of context node and the parent's
1583 * parent and so on; the nodes are ordered in reverse document order; thus the
1584 * parent is the first node on the axis, and the parent's parent is the second
1585 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001586 *
1587 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001588 */
1589xmlNodePtr
1590xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1591 /*
1592 * !!!!!!!!!!!!!
1593 * the parent of an attribute or namespace node is the element
1594 * to which the attribute or namespace node is attached
1595 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001596 if (cur == NULL) {
1597 if (ctxt->context->node->parent == NULL)
1598 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001599 return(ctxt->context->node->parent);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001600 }
1601 if (cur == ctxt->context->doc->root)
1602 return((xmlNodePtr) ctxt->context->doc);
1603 if (cur == (xmlNodePtr) ctxt->context->doc)
1604 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001605 return(cur->parent);
1606}
1607
1608/**
1609 * xmlXPathNextAncestorOrSelf:
1610 * @ctxt: the XPath Parser context
1611 * @cur: the current node in the traversal
1612 *
1613 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001614 * he ancestor-or-self axis contains the context node and ancestors of
1615 * the context node in reverse document order; thus the context node is
1616 * the first node on the axis, and the context node's parent the second;
1617 * parent here is defined the same as with the parent axis.
1618 *
1619 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001620 */
1621xmlNodePtr
1622xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1623 /*
1624 * !!!!!!!!!!!!!
1625 * the parent of an attribute or namespace node is the element
1626 * to which the attribute or namespace node is attached
1627 */
1628 if (cur == NULL)
1629 return(ctxt->context->node);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001630 if (cur == ctxt->context->doc->root)
1631 return((xmlNodePtr) ctxt->context->doc);
1632 if (cur == (xmlNodePtr) ctxt->context->doc)
1633 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001634 return(cur->parent);
1635}
1636
1637/**
1638 * xmlXPathNextFollowingSibling:
1639 * @ctxt: the XPath Parser context
1640 * @cur: the current node in the traversal
1641 *
1642 * Traversal function for the "following-sibling" direction
1643 * The following-sibling axis contains the following siblings of the context
1644 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001645 *
1646 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001647 */
1648xmlNodePtr
1649xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001650 if (cur == (xmlNodePtr) ctxt->context->doc)
1651 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001652 if (cur == NULL)
1653 return(ctxt->context->node->next);
1654 return(cur->next);
1655}
1656
1657/**
1658 * xmlXPathNextPrecedingSibling:
1659 * @ctxt: the XPath Parser context
1660 * @cur: the current node in the traversal
1661 *
1662 * Traversal function for the "preceding-sibling" direction
1663 * The preceding-sibling axis contains the preceding siblings of the context
1664 * node in reverse document order; the first preceding sibling is first on the
1665 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001666 *
1667 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001668 */
1669xmlNodePtr
1670xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001671 if (cur == (xmlNodePtr) ctxt->context->doc)
1672 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001673 if (cur == NULL)
1674 return(ctxt->context->node->prev);
1675 return(cur->prev);
1676}
1677
1678/**
1679 * xmlXPathNextFollowing:
1680 * @ctxt: the XPath Parser context
1681 * @cur: the current node in the traversal
1682 *
1683 * Traversal function for the "following" direction
1684 * The following axis contains all nodes in the same document as the context
1685 * node that are after the context node in document order, excluding any
1686 * descendants and excluding attribute nodes and namespace nodes; the nodes
1687 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001688 *
1689 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001690 */
1691xmlNodePtr
1692xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001693 if (cur == (xmlNodePtr) ctxt->context->doc)
1694 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001695 if (cur == NULL)
1696 return(ctxt->context->node->next);; /* !!!!!!!!! */
1697 if (cur->childs != NULL) return(cur->childs);
1698 if (cur->next != NULL) return(cur->next);
1699
1700 do {
1701 cur = cur->parent;
1702 if (cur == NULL) return(NULL);
1703 if (cur == ctxt->context->doc->root) return(NULL);
1704 if (cur->next != NULL) {
1705 cur = cur->next;
1706 return(cur);
1707 }
1708 } while (cur != NULL);
1709 return(cur);
1710}
1711
1712/**
1713 * xmlXPathNextPreceding:
1714 * @ctxt: the XPath Parser context
1715 * @cur: the current node in the traversal
1716 *
1717 * Traversal function for the "preceding" direction
1718 * the preceding axis contains all nodes in the same document as the context
1719 * node that are before the context node in document order, excluding any
1720 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1721 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001722 *
1723 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001724 */
1725xmlNodePtr
1726xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001727 if (cur == (xmlNodePtr) ctxt->context->doc)
1728 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001729 if (cur == NULL)
1730 return(ctxt->context->node->prev); /* !!!!!!!!! */
1731 if (cur->last != NULL) return(cur->last);
1732 if (cur->prev != NULL) return(cur->prev);
1733
1734 do {
1735 cur = cur->parent;
1736 if (cur == NULL) return(NULL);
1737 if (cur == ctxt->context->doc->root) return(NULL);
1738 if (cur->prev != NULL) {
1739 cur = cur->prev;
1740 return(cur);
1741 }
1742 } while (cur != NULL);
1743 return(cur);
1744}
1745
1746/**
1747 * xmlXPathNextNamespace:
1748 * @ctxt: the XPath Parser context
1749 * @cur: the current attribute in the traversal
1750 *
1751 * Traversal function for the "namespace" direction
1752 * the namespace axis contains the namespace nodes of the context node;
1753 * the order of nodes on this axis is implementation-defined; the axis will
1754 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001755 *
1756 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001757 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001758xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001759xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001760 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1761 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001762 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001763 ctxt->context->namespaces =
1764 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1765 if (ctxt->context->namespaces == NULL) return(NULL);
1766 ctxt->context->nsNr = 0;
1767 }
1768 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001769}
1770
1771/**
1772 * xmlXPathNextAttribute:
1773 * @ctxt: the XPath Parser context
1774 * @cur: the current attribute in the traversal
1775 *
1776 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001777 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001778 *
1779 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001780 */
1781xmlAttrPtr
1782xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001783 if (cur == NULL) {
1784 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1785 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001786 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001787 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001788 return(cur->next);
1789}
1790
1791/************************************************************************
1792 * *
1793 * NodeTest Functions *
1794 * *
1795 ************************************************************************/
1796
1797#define NODE_TEST_NONE 0
1798#define NODE_TEST_TYPE 1
1799#define NODE_TEST_PI 2
1800#define NODE_TEST_ALL 3
1801#define NODE_TEST_NS 4
1802#define NODE_TEST_NAME 5
1803
1804#define NODE_TYPE_COMMENT 50
1805#define NODE_TYPE_TEXT 51
1806#define NODE_TYPE_PI 52
1807#define NODE_TYPE_NODE 53
1808
1809#define IS_FUNCTION 200
1810
1811/**
1812 * xmlXPathNodeCollectAndTest:
1813 * @ctxt: the XPath Parser context
1814 * @cur: the current node to test
1815 *
1816 * This is the function implementing a step: based on the current list
1817 * of nodes, it builds up a new list, looking at all nodes under that
1818 * axis and selecting them.
1819 *
1820 * Returns the new NodeSet resulting from the search.
1821 */
1822xmlNodeSetPtr
1823xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001824 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001825#ifdef DEBUG_STEP
1826 int n = 0, t = 0;
1827#endif
1828 int i;
1829 xmlNodeSetPtr ret;
1830 xmlXPathTraversalFunction next = NULL;
1831 xmlNodePtr cur = NULL;
1832
1833 if (ctxt->context->nodelist == NULL) {
1834 if (ctxt->context->node == NULL) {
1835 fprintf(xmlXPathDebug,
1836 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1837 __FILE__, __LINE__);
1838 return(NULL);
1839 }
1840 STRANGE
1841 return(NULL);
1842 }
1843#ifdef DEBUG_STEP
1844 fprintf(xmlXPathDebug, "new step : ");
1845#endif
1846 switch (axis) {
1847 case AXIS_ANCESTOR:
1848#ifdef DEBUG_STEP
1849 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1850#endif
1851 next = xmlXPathNextAncestor; break;
1852 case AXIS_ANCESTOR_OR_SELF:
1853#ifdef DEBUG_STEP
1854 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1855#endif
1856 next = xmlXPathNextAncestorOrSelf; break;
1857 case AXIS_ATTRIBUTE:
1858#ifdef DEBUG_STEP
1859 fprintf(xmlXPathDebug, "axis 'attributes' ");
1860#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001861 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001862 break;
1863 case AXIS_CHILD:
1864#ifdef DEBUG_STEP
1865 fprintf(xmlXPathDebug, "axis 'child' ");
1866#endif
1867 next = xmlXPathNextChild; break;
1868 case AXIS_DESCENDANT:
1869#ifdef DEBUG_STEP
1870 fprintf(xmlXPathDebug, "axis 'descendant' ");
1871#endif
1872 next = xmlXPathNextDescendant; break;
1873 case AXIS_DESCENDANT_OR_SELF:
1874#ifdef DEBUG_STEP
1875 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1876#endif
1877 next = xmlXPathNextDescendantOrSelf; break;
1878 case AXIS_FOLLOWING:
1879#ifdef DEBUG_STEP
1880 fprintf(xmlXPathDebug, "axis 'following' ");
1881#endif
1882 next = xmlXPathNextFollowing; break;
1883 case AXIS_FOLLOWING_SIBLING:
1884#ifdef DEBUG_STEP
1885 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1886#endif
1887 next = xmlXPathNextFollowingSibling; break;
1888 case AXIS_NAMESPACE:
1889#ifdef DEBUG_STEP
1890 fprintf(xmlXPathDebug, "axis 'namespace' ");
1891#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001892 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001893 break;
1894 case AXIS_PARENT:
1895#ifdef DEBUG_STEP
1896 fprintf(xmlXPathDebug, "axis 'parent' ");
1897#endif
1898 next = xmlXPathNextParent; break;
1899 case AXIS_PRECEDING:
1900#ifdef DEBUG_STEP
1901 fprintf(xmlXPathDebug, "axis 'preceding' ");
1902#endif
1903 next = xmlXPathNextPreceding; break;
1904 case AXIS_PRECEDING_SIBLING:
1905#ifdef DEBUG_STEP
1906 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1907#endif
1908 next = xmlXPathNextPrecedingSibling; break;
1909 case AXIS_SELF:
1910#ifdef DEBUG_STEP
1911 fprintf(xmlXPathDebug, "axis 'self' ");
1912#endif
1913 next = xmlXPathNextSelf; break;
1914 }
1915 if (next == NULL) return(NULL);
1916 ret = xmlXPathNodeSetCreate(NULL);
1917#ifdef DEBUG_STEP
1918 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1919 ctxt->context->nodelist->nodeNr);
1920 switch (test) {
1921 case NODE_TEST_NONE:
1922 fprintf(xmlXPathDebug, " seaching for none !!!\n");
1923 break;
1924 case NODE_TEST_TYPE:
1925 fprintf(xmlXPathDebug, " seaching for type %d\n", type);
1926 break;
1927 case NODE_TEST_PI:
1928 fprintf(xmlXPathDebug, " seaching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001929 break;
1930 case NODE_TEST_ALL:
1931 fprintf(xmlXPathDebug, " seaching for *\n");
1932 break;
1933 case NODE_TEST_NS:
1934 fprintf(xmlXPathDebug, " seaching for namespace %s\n",
1935 prefix);
1936 break;
1937 case NODE_TEST_NAME:
1938 fprintf(xmlXPathDebug, " seaching for name %s\n", name);
1939 if (prefix != NULL)
1940 fprintf(xmlXPathDebug, " with namespace %s\n",
1941 prefix);
1942 break;
1943 }
1944 fprintf(xmlXPathDebug, "Testing : ");
1945#endif
1946 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1947 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1948
1949 cur = NULL;
1950 do {
1951 cur = next(ctxt, cur);
1952 if (cur == NULL) break;
1953#ifdef DEBUG_STEP
1954 t++;
1955 fprintf(xmlXPathDebug, " %s", cur->name);
1956#endif
1957 switch (test) {
1958 case NODE_TEST_NONE:
1959 STRANGE
1960 return(NULL);
1961 case NODE_TEST_TYPE:
1962 if (cur->type == type) {
1963#ifdef DEBUG_STEP
1964 n++;
1965#endif
1966 xmlXPathNodeSetAdd(ret, cur);
1967 }
1968 break;
1969 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001970 if (cur->type == XML_PI_NODE) {
1971 if ((name != NULL) &&
1972 (xmlStrcmp(name, cur->name)))
1973 break;
1974#ifdef DEBUG_STEP
1975 n++;
1976#endif
1977 xmlXPathNodeSetAdd(ret, cur);
1978 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001979 break;
1980 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001981 if ((cur->type == XML_ELEMENT_NODE) ||
1982 (cur->type == XML_ATTRIBUTE_NODE)) {
1983 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001984#ifdef DEBUG_STEP
1985 n++;
1986#endif
1987 xmlXPathNodeSetAdd(ret, cur);
1988 }
1989 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001990 case NODE_TEST_NS: {
1991 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001992 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001993 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001994 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001995 switch (cur->type) {
1996 case XML_ELEMENT_NODE:
1997 if (!xmlStrcmp(name, cur->name) &&
1998 (((prefix == NULL) ||
1999 ((cur->ns != NULL) &&
2000 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002001#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002002 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002003#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002004 xmlXPathNodeSetAdd(ret, cur);
2005 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002006 break;
2007 case XML_ATTRIBUTE_NODE: {
2008 xmlAttrPtr attr = (xmlAttrPtr) cur;
2009 if (!xmlStrcmp(name, attr->name)) {
2010#ifdef DEBUG_STEP
2011 n++;
2012#endif
2013 xmlXPathNodeSetAdd(ret, cur);
2014 }
2015 break;
2016 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002017 default:
2018 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002019 }
2020 break;
2021
2022 }
2023 } while (cur != NULL);
2024 }
2025#ifdef DEBUG_STEP
2026 fprintf(xmlXPathDebug,
2027 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2028#endif
2029 return(ret);
2030}
2031
2032
2033/************************************************************************
2034 * *
2035 * Implicit tree core function library *
2036 * *
2037 ************************************************************************/
2038
2039/**
2040 * xmlXPathRoot:
2041 * @ctxt: the XPath Parser context
2042 *
2043 * Initialize the context to the root of the document
2044 */
2045void
2046xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2047 if (ctxt->context->nodelist != NULL)
2048 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002049 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2050 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002051}
2052
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002053/************************************************************************
2054 * *
2055 * The explicit core function library *
2056 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2057 * *
2058 ************************************************************************/
2059
2060
2061/**
2062 * xmlXPathLastFunction:
2063 * @ctxt: the XPath Parser context
2064 *
2065 * Implement the last() XPath function
2066 * The last function returns the number of nodes in the context node list.
2067 */
2068void
2069xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2070 CHECK_ARITY(0);
2071 if ((ctxt->context->nodelist == NULL) ||
2072 (ctxt->context->node == NULL) ||
2073 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002074 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002075 } else {
2076 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002077 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002078 }
2079}
2080
2081/**
2082 * xmlXPathPositionFunction:
2083 * @ctxt: the XPath Parser context
2084 *
2085 * Implement the position() XPath function
2086 * The position function returns the position of the context node in the
2087 * context node list. The first position is 1, and so the last positionr
2088 * will be equal to last().
2089 */
2090void
2091xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2092 int i;
2093
2094 CHECK_ARITY(0);
2095 if ((ctxt->context->nodelist == NULL) ||
2096 (ctxt->context->node == NULL) ||
2097 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002098 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002099 }
2100 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2101 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002102 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002103 return;
2104 }
2105 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002106 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002107}
2108
2109/**
2110 * xmlXPathCountFunction:
2111 * @ctxt: the XPath Parser context
2112 *
2113 * Implement the count() XPath function
2114 */
2115void
2116xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2117 xmlXPathObjectPtr cur;
2118
2119 CHECK_ARITY(1);
2120 CHECK_TYPE(XPATH_NODESET);
2121 cur = valuePop(ctxt);
2122
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002123 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002124 xmlXPathFreeObject(cur);
2125}
2126
2127/**
2128 * xmlXPathIdFunction:
2129 * @ctxt: the XPath Parser context
2130 *
2131 * Implement the id() XPath function
2132 * The id function selects elements by their unique ID
2133 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2134 * then the result is the union of the result of applying id to the
2135 * string value of each of the nodes in the argument node-set. When the
2136 * argument to id is of any other type, the argument is converted to a
2137 * string as if by a call to the string function; the string is split
2138 * into a whitespace-separated list of tokens (whitespace is any sequence
2139 * of characters matching the production S); the result is a node-set
2140 * containing the elements in the same document as the context node that
2141 * have a unique ID equal to any of the tokens in the list.
2142 */
2143void
2144xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002145 const xmlChar *tokens;
2146 const xmlChar *cur;
2147 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002148 xmlAttrPtr attr;
2149 xmlNodePtr elem = NULL;
2150 xmlXPathObjectPtr ret, obj;
2151
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002152 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002153 obj = valuePop(ctxt);
2154 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2155 if (obj->type == XPATH_NODESET) {
2156 TODO /* ID function in case of NodeSet */
2157 }
2158 if (obj->type != XPATH_STRING) {
2159 valuePush(ctxt, obj);
2160 xmlXPathStringFunction(ctxt, 1);
2161 obj = valuePop(ctxt);
2162 if (obj->type != XPATH_STRING) {
2163 xmlXPathFreeObject(obj);
2164 return;
2165 }
2166 }
2167 tokens = obj->stringval;
2168
2169 ret = xmlXPathNewNodeSet(NULL);
2170 valuePush(ctxt, ret);
2171 if (tokens == NULL) {
2172 xmlXPathFreeObject(obj);
2173 return;
2174 }
2175
2176 cur = tokens;
2177
2178 while (IS_BLANK(*cur)) cur++;
2179 while (*cur != 0) {
2180 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2181 (*cur == '.') || (*cur == '-') ||
2182 (*cur == '_') || (*cur == ':') ||
2183 (IS_COMBINING(*cur)) ||
2184 (IS_EXTENDER(*cur)))
2185 cur++;
2186
2187 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2188
2189 ID = xmlStrndup(tokens, cur - tokens);
2190 attr = xmlGetID(ctxt->context->doc, ID);
2191 if (attr != NULL) {
2192 elem = attr->node;
2193 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2194 }
2195 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002196 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002197
2198 while (IS_BLANK(*cur)) cur++;
2199 tokens = cur;
2200 }
2201 xmlXPathFreeObject(obj);
2202 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002203}
2204
2205/**
2206 * xmlXPathLocalPartFunction:
2207 * @ctxt: the XPath Parser context
2208 *
2209 * Implement the local-part() XPath function
2210 * The local-part function returns a string containing the local part
2211 * of the name of the node in the argument node-set that is first in
2212 * document order. If the node-set is empty or the first node has no
2213 * name, an empty string is returned. If the argument is omitted it
2214 * defaults to the context node.
2215 */
2216void
2217xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2218 xmlXPathObjectPtr cur;
2219
2220 CHECK_ARITY(1);
2221 CHECK_TYPE(XPATH_NODESET);
2222 cur = valuePop(ctxt);
2223
2224 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002225 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002226 } else {
2227 int i = 0; /* Should be first in document order !!!!! */
2228 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2229 }
2230 xmlXPathFreeObject(cur);
2231}
2232
2233/**
2234 * xmlXPathNamespaceFunction:
2235 * @ctxt: the XPath Parser context
2236 *
2237 * Implement the namespace() XPath function
2238 * The namespace function returns a string containing the namespace URI
2239 * of the expanded name of the node in the argument node-set that is
2240 * first in document order. If the node-set is empty, the first node has
2241 * no name, or the expanded name has no namespace URI, an empty string
2242 * is returned. If the argument is omitted it defaults to the context node.
2243 */
2244void
2245xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2246 xmlXPathObjectPtr cur;
2247
Daniel Veillardb96e6431999-08-29 21:02:19 +00002248 if (nargs == 0) {
2249 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2250 nargs = 1;
2251 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002252 CHECK_ARITY(1);
2253 CHECK_TYPE(XPATH_NODESET);
2254 cur = valuePop(ctxt);
2255
2256 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002257 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002258 } else {
2259 int i = 0; /* Should be first in document order !!!!! */
2260
2261 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002262 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002263 else
2264 valuePush(ctxt, xmlXPathNewString(
2265 cur->nodesetval->nodeTab[i]->ns->href));
2266 }
2267 xmlXPathFreeObject(cur);
2268}
2269
2270/**
2271 * xmlXPathNameFunction:
2272 * @ctxt: the XPath Parser context
2273 *
2274 * Implement the name() XPath function
2275 * The name function returns a string containing a QName representing
2276 * the name of the node in the argument node-set that is first in documenti
2277 * order. The QName must represent the name with respect to the namespace
2278 * declarations in effect on the node whose name is being represented.
2279 * Typically, this will be the form in which the name occurred in the XML
2280 * source. This need not be the case if there are namespace declarations
2281 * in effect on the node that associate multiple prefixes with the same
2282 * namespace. However, an implementation may include information about
2283 * the original prefix in its representation of nodes; in this case, an
2284 * implementation can ensure that the returned string is always the same
2285 * as the QName used in the XML source. If the argument it omitted it
2286 * defaults to the context node.
2287 * Libxml keep the original prefix so the "real qualified name" used is
2288 * returned.
2289 */
2290void
2291xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2292 xmlXPathObjectPtr cur;
2293
2294 CHECK_ARITY(1);
2295 CHECK_TYPE(XPATH_NODESET);
2296 cur = valuePop(ctxt);
2297
2298 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002299 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002300 } else {
2301 int i = 0; /* Should be first in document order !!!!! */
2302
2303 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2304 valuePush(ctxt, xmlXPathNewString(
2305 cur->nodesetval->nodeTab[i]->name));
2306
2307 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002308 char name[2000];
2309 sprintf(name, "%s:%s",
2310 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2311 (char *) cur->nodesetval->nodeTab[i]->name);
2312 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002313 }
2314 }
2315 xmlXPathFreeObject(cur);
2316}
2317
2318/**
2319 * xmlXPathStringFunction:
2320 * @ctxt: the XPath Parser context
2321 *
2322 * Implement the string() XPath function
2323 * he string function converts an object to a string as follows:
2324 * - A node-set is converted to a string by returning the value of
2325 * the node in the node-set that is first in document order.
2326 * If the node-set is empty, an empty string is returned.
2327 * - A number is converted to a string as follows
2328 * + NaN is converted to the string NaN
2329 * + positive zero is converted to the string 0
2330 * + negative zero is converted to the string 0
2331 * + positive infinity is converted to the string Infinity
2332 * + negative infinity is converted to the string -Infinity
2333 * + if the number is an integer, the number is represented in
2334 * decimal form as a Number with no decimal point and no leading
2335 * zeros, preceded by a minus sign (-) if the number is negative
2336 * + otherwise, the number is represented in decimal form as a
2337 * Number including a decimal point with at least one digit
2338 * before the decimal point and at least one digit after the
2339 * decimal point, preceded by a minus sign (-) if the number
2340 * is negative; there must be no leading zeros before the decimal
2341 * point apart possibly from the one required digit immediatelyi
2342 * before the decimal point; beyond the one required digit
2343 * after the decimal point there must be as many, but only as
2344 * many, more digits as are needed to uniquely distinguish the
2345 * number from all other IEEE 754 numeric values.
2346 * - The boolean false value is converted to the string false.
2347 * The boolean true value is converted to the string true.
2348 */
2349void
2350xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2351 xmlXPathObjectPtr cur;
2352
2353 CHECK_ARITY(1);
2354 cur = valuePop(ctxt);
2355 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2356 switch (cur->type) {
2357 case XPATH_NODESET:
2358 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002359 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002360 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002361 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002362 int i = 0; /* Should be first in document order !!!!! */
2363 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2364 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002365 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002366 }
2367 xmlXPathFreeObject(cur);
2368 return;
2369 case XPATH_STRING:
2370 valuePush(ctxt, cur);
2371 return;
2372 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002373 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2374 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002375 xmlXPathFreeObject(cur);
2376 return;
2377 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002378 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002379
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002380 if (isnan(cur->floatval))
2381 sprintf(buf, "NaN");
2382 else if (isinf(cur->floatval) > 0)
2383 sprintf(buf, "+Infinity");
2384 else if (isinf(cur->floatval) < 0)
2385 sprintf(buf, "-Infinity");
2386 else
2387 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002388 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002389 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002390 return;
2391 }
2392 }
2393 STRANGE
2394}
2395
2396/**
2397 * xmlXPathStringLengthFunction:
2398 * @ctxt: the XPath Parser context
2399 *
2400 * Implement the string-length() XPath function
2401 * The string-length returns the number of characters in the string
2402 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2403 * the context node converted to a string, in other words the value
2404 * of the context node.
2405 */
2406void
2407xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2408 xmlXPathObjectPtr cur;
2409
2410 if (nargs == 0) {
2411 if (ctxt->context->node == NULL) {
2412 valuePush(ctxt, xmlXPathNewFloat(0));
2413 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002414 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002415
2416 content = xmlNodeGetContent(ctxt->context->node);
2417 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002418 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002419 }
2420 return;
2421 }
2422 CHECK_ARITY(1);
2423 CHECK_TYPE(XPATH_STRING);
2424 cur = valuePop(ctxt);
2425 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2426 xmlXPathFreeObject(cur);
2427}
2428
2429/**
2430 * xmlXPathConcatFunction:
2431 * @ctxt: the XPath Parser context
2432 *
2433 * Implement the concat() XPath function
2434 * The concat function returns the concatenation of its arguments.
2435 */
2436void
2437xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2438 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002439 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002440
2441 if (nargs < 2) {
2442 CHECK_ARITY(2);
2443 }
2444
2445 cur = valuePop(ctxt);
2446 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2447 xmlXPathFreeObject(cur);
2448 return;
2449 }
2450 nargs--;
2451
2452 while (nargs > 0) {
2453 new = valuePop(ctxt);
2454 if ((new == NULL) || (new->type != XPATH_STRING)) {
2455 xmlXPathFreeObject(new);
2456 xmlXPathFreeObject(cur);
2457 ERROR(XPATH_INVALID_TYPE);
2458 }
2459 tmp = xmlStrcat(new->stringval, cur->stringval);
2460 new->stringval = cur->stringval;
2461 cur->stringval = tmp;
2462
2463 xmlXPathFreeObject(new);
2464 nargs--;
2465 }
2466 valuePush(ctxt, cur);
2467}
2468
2469/**
2470 * xmlXPathContainsFunction:
2471 * @ctxt: the XPath Parser context
2472 *
2473 * Implement the contains() XPath function
2474 * The contains function returns true if the first argument string
2475 * contains the second argument string, and otherwise returns false.
2476 */
2477void
2478xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2479 xmlXPathObjectPtr hay, needle;
2480
2481 CHECK_ARITY(2);
2482 CHECK_TYPE(XPATH_STRING);
2483 needle = valuePop(ctxt);
2484 hay = valuePop(ctxt);
2485 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2486 xmlXPathFreeObject(hay);
2487 xmlXPathFreeObject(needle);
2488 ERROR(XPATH_INVALID_TYPE);
2489 }
2490 if (xmlStrstr(hay->stringval, needle->stringval))
2491 valuePush(ctxt, xmlXPathNewBoolean(1));
2492 else
2493 valuePush(ctxt, xmlXPathNewBoolean(0));
2494 xmlXPathFreeObject(hay);
2495 xmlXPathFreeObject(needle);
2496}
2497
2498/**
2499 * xmlXPathStartsWithFunction:
2500 * @ctxt: the XPath Parser context
2501 *
2502 * Implement the starts-with() XPath function
2503 * The starts-with function returns true if the first argument string
2504 * starts with the second argument string, and otherwise returns false.
2505 */
2506void
2507xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2508 xmlXPathObjectPtr hay, needle;
2509 int n;
2510
2511 CHECK_ARITY(2);
2512 CHECK_TYPE(XPATH_STRING);
2513 needle = valuePop(ctxt);
2514 hay = valuePop(ctxt);
2515 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2516 xmlXPathFreeObject(hay);
2517 xmlXPathFreeObject(needle);
2518 ERROR(XPATH_INVALID_TYPE);
2519 }
2520 n = xmlStrlen(needle->stringval);
2521 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2522 valuePush(ctxt, xmlXPathNewBoolean(0));
2523 else
2524 valuePush(ctxt, xmlXPathNewBoolean(1));
2525 xmlXPathFreeObject(hay);
2526 xmlXPathFreeObject(needle);
2527}
2528
2529/**
2530 * xmlXPathSubstringFunction:
2531 * @ctxt: the XPath Parser context
2532 *
2533 * Implement the substring() XPath function
2534 * The substring function returns the substring of the first argument
2535 * starting at the position specified in the second argument with
2536 * length specified in the third argument. For example,
2537 * substring("12345",2,3) returns "234". If the third argument is not
2538 * specified, it returns the substring starting at the position specified
2539 * in the second argument and continuing to the end of the string. For
2540 * example, substring("12345",2) returns "2345". More precisely, each
2541 * character in the string (see [3.6 Strings]) is considered to have a
2542 * numeric position: the position of the first character is 1, the position
2543 * of the second character is 2 and so on. The returned substring contains
2544 * those characters for which the position of the character is greater than
2545 * or equal to the second argument and, if the third argument is specified,
2546 * less than the sum of the second and third arguments; the comparisons
2547 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2548 * - substring("12345", 1.5, 2.6) returns "234"
2549 * - substring("12345", 0, 3) returns "12"
2550 * - substring("12345", 0 div 0, 3) returns ""
2551 * - substring("12345", 1, 0 div 0) returns ""
2552 * - substring("12345", -42, 1 div 0) returns "12345"
2553 * - substring("12345", -1 div 0, 1 div 0) returns ""
2554 */
2555void
2556xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2557 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002558 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002559 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002560 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002561
2562 /*
2563 * Conformance needs to be checked !!!!!
2564 */
2565 if (nargs < 2) {
2566 CHECK_ARITY(2);
2567 }
2568 if (nargs > 3) {
2569 CHECK_ARITY(3);
2570 }
2571 if (nargs == 3) {
2572 CHECK_TYPE(XPATH_NUMBER);
2573 len = valuePop(ctxt);
2574 le = len->floatval;
2575 xmlXPathFreeObject(len);
2576 } else {
2577 le = 2000000000;
2578 }
2579 CHECK_TYPE(XPATH_NUMBER);
2580 start = valuePop(ctxt);
2581 in = start->floatval;
2582 xmlXPathFreeObject(start);
2583 CHECK_TYPE(XPATH_STRING);
2584 str = valuePop(ctxt);
2585 le += in;
2586
2587 /* integer index of the first char */
2588 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002589 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002590
2591 /* integer index of the last char */
2592 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002593 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002594
2595 /* back to a zero based len */
2596 i--;
2597 l--;
2598
2599 /* check against the string len */
2600 if (l > 1024) {
2601 l = xmlStrlen(str->stringval);
2602 }
2603 if (i < 0) {
2604 i = 0;
2605 }
2606
2607 /* number of chars to copy */
2608 l -= i;
2609
2610 ret = xmlStrsub(str->stringval, i, l);
2611 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002612 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002613 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002614 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002615 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002616 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002617 xmlXPathFreeObject(str);
2618}
2619
2620/**
2621 * xmlXPathSubstringBeforeFunction:
2622 * @ctxt: the XPath Parser context
2623 *
2624 * Implement the substring-before() XPath function
2625 * The substring-before function returns the substring of the first
2626 * argument string that precedes the first occurrence of the second
2627 * argument string in the first argument string, or the empty string
2628 * if the first argument string does not contain the second argument
2629 * string. For example, substring-before("1999/04/01","/") returns 1999.
2630 */
2631void
2632xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2633 CHECK_ARITY(2);
2634 TODO /* substring before */
2635}
2636
2637/**
2638 * xmlXPathSubstringAfterFunction:
2639 * @ctxt: the XPath Parser context
2640 *
2641 * Implement the substring-after() XPath function
2642 * The substring-after function returns the substring of the first
2643 * argument string that follows the first occurrence of the second
2644 * argument string in the first argument string, or the empty stringi
2645 * if the first argument string does not contain the second argument
2646 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2647 * and substring-after("1999/04/01","19") returns 99/04/01.
2648 */
2649void
2650xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2651 CHECK_ARITY(2);
2652 TODO /* substring after */
2653}
2654
2655/**
2656 * xmlXPathNormalizeFunction:
2657 * @ctxt: the XPath Parser context
2658 *
2659 * Implement the normalize() XPath function
2660 * The normalize function returns the argument string with white
2661 * space normalized by stripping leading and trailing whitespace
2662 * and replacing sequences of whitespace characters by a single
2663 * space. Whitespace characters are the same allowed by the S production
2664 * in XML. If the argument is omitted, it defaults to the context
2665 * node converted to a string, in other words the value of the context node.
2666 */
2667void
2668xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2669 CHECK_ARITY(1);
2670 TODO /* normalize isn't as boring as translate, but pretty much */
2671}
2672
2673/**
2674 * xmlXPathTranslateFunction:
2675 * @ctxt: the XPath Parser context
2676 *
2677 * Implement the translate() XPath function
2678 * The translate function returns the first argument string with
2679 * occurrences of characters in the second argument string replaced
2680 * by the character at the corresponding position in the third argument
2681 * string. For example, translate("bar","abc","ABC") returns the string
2682 * BAr. If there is a character in the second argument string with no
2683 * character at a corresponding position in the third argument string
2684 * (because the second argument string is longer than the third argument
2685 * string), then occurrences of that character in the first argument
2686 * string are removed. For example, translate("--aaa--","abc-","ABC")
2687 * returns "AAA". If a character occurs more than once in second
2688 * argument string, then the first occurrence determines the replacement
2689 * character. If the third argument string is longer than the second
2690 * argument string, then excess characters are ignored.
2691 */
2692void
2693xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2694 CHECK_ARITY(3);
2695 TODO /* translate is boring, waiting for UTF-8 representation too */
2696}
2697
2698/**
2699 * xmlXPathBooleanFunction:
2700 * @ctxt: the XPath Parser context
2701 *
2702 * Implement the boolean() XPath function
2703 * he boolean function converts its argument to a boolean as follows:
2704 * - a number is true if and only if it is neither positive or
2705 * negative zero nor NaN
2706 * - a node-set is true if and only if it is non-empty
2707 * - a string is true if and only if its length is non-zero
2708 */
2709void
2710xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2711 xmlXPathObjectPtr cur;
2712 int res = 0;
2713
2714 CHECK_ARITY(1);
2715 cur = valuePop(ctxt);
2716 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2717 switch (cur->type) {
2718 case XPATH_NODESET:
2719 if ((cur->nodesetval == NULL) ||
2720 (cur->nodesetval->nodeNr == 0)) res = 0;
2721 else
2722 res = 1;
2723 break;
2724 case XPATH_STRING:
2725 if ((cur->stringval == NULL) ||
2726 (cur->stringval[0] == 0)) res = 0;
2727 else
2728 res = 1;
2729 break;
2730 case XPATH_BOOLEAN:
2731 valuePush(ctxt, cur);
2732 return;
2733 case XPATH_NUMBER:
2734 if (cur->floatval) res = 1;
2735 break;
2736 default:
2737 STRANGE
2738 }
2739 xmlXPathFreeObject(cur);
2740 valuePush(ctxt, xmlXPathNewBoolean(res));
2741}
2742
2743/**
2744 * xmlXPathNotFunction:
2745 * @ctxt: the XPath Parser context
2746 *
2747 * Implement the not() XPath function
2748 * The not function returns true if its argument is false,
2749 * and false otherwise.
2750 */
2751void
2752xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2753 CHECK_ARITY(1);
2754 CHECK_TYPE(XPATH_BOOLEAN);
2755 ctxt->value->boolval = ! ctxt->value->boolval;
2756}
2757
2758/**
2759 * xmlXPathTrueFunction:
2760 * @ctxt: the XPath Parser context
2761 *
2762 * Implement the true() XPath function
2763 */
2764void
2765xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2766 CHECK_ARITY(0);
2767 valuePush(ctxt, xmlXPathNewBoolean(1));
2768}
2769
2770/**
2771 * xmlXPathFalseFunction:
2772 * @ctxt: the XPath Parser context
2773 *
2774 * Implement the false() XPath function
2775 */
2776void
2777xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2778 CHECK_ARITY(0);
2779 valuePush(ctxt, xmlXPathNewBoolean(0));
2780}
2781
2782/**
2783 * xmlXPathLangFunction:
2784 * @ctxt: the XPath Parser context
2785 *
2786 * Implement the lang() XPath function
2787 * The lang function returns true or false depending on whether the
2788 * language of the context node as specified by xml:lang attributes
2789 * is the same as or is a sublanguage of the language specified by
2790 * the argument string. The language of the context node is determined
2791 * by the value of the xml:lang attribute on the context node, or, if
2792 * the context node has no xml:lang attribute, by the value of the
2793 * xml:lang attribute on the nearest ancestor of the context node that
2794 * has an xml:lang attribute. If there is no such attribute, then lang
2795 * returns false. If there is such an attribute, then lang returns
2796 * true if the attribute value is equal to the argument ignoring case,
2797 * or if there is some suffix starting with - such that the attribute
2798 * value is equal to the argument ignoring that suffix of the attribute
2799 * value and ignoring case.
2800 */
2801void
2802xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002803 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002804 const xmlChar *theLang;
2805 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002806 int ret = 0;
2807 int i;
2808
2809 CHECK_ARITY(1);
2810 CHECK_TYPE(XPATH_STRING);
2811 val = valuePop(ctxt);
2812 lang = val->stringval;
2813 theLang = xmlNodeGetLang(ctxt->context->node);
2814 if ((theLang != NULL) && (lang != NULL)) {
2815 for (i = 0;lang[i] != 0;i++)
2816 if (toupper(lang[i]) != toupper(theLang[i]))
2817 goto not_equal;
2818 ret = 1;
2819 }
2820not_equal:
2821 xmlXPathFreeObject(val);
2822 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002823}
2824
2825/**
2826 * xmlXPathNumberFunction:
2827 * @ctxt: the XPath Parser context
2828 *
2829 * Implement the number() XPath function
2830 */
2831void
2832xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2833 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002834 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002835
2836 CHECK_ARITY(1);
2837 cur = valuePop(ctxt);
2838 switch (cur->type) {
2839 case XPATH_NODESET:
2840 valuePush(ctxt, cur);
2841 xmlXPathStringFunction(ctxt, 1);
2842 cur = valuePop(ctxt);
2843 case XPATH_STRING:
2844 res = xmlXPathStringEvalNumber(cur->stringval);
2845 valuePush(ctxt, xmlXPathNewFloat(res));
2846 xmlXPathFreeObject(cur);
2847 return;
2848 case XPATH_BOOLEAN:
2849 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2850 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2851 xmlXPathFreeObject(cur);
2852 return;
2853 case XPATH_NUMBER:
2854 valuePush(ctxt, cur);
2855 return;
2856 }
2857 STRANGE
2858}
2859
2860/**
2861 * xmlXPathSumFunction:
2862 * @ctxt: the XPath Parser context
2863 *
2864 * Implement the sum() XPath function
2865 * The sum function returns the sum of the values of the nodes in
2866 * the argument node-set.
2867 */
2868void
2869xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2870 CHECK_ARITY(1);
2871 TODO /* BUG Sum : don't understand the definition */
2872}
2873
2874/**
2875 * xmlXPathFloorFunction:
2876 * @ctxt: the XPath Parser context
2877 *
2878 * Implement the floor() XPath function
2879 * The floor function returns the largest (closest to positive infinity)
2880 * number that is not greater than the argument and that is an integer.
2881 */
2882void
2883xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2884 CHECK_ARITY(1);
2885 CHECK_TYPE(XPATH_NUMBER);
2886 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002887 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002888}
2889
2890/**
2891 * xmlXPathCeilingFunction:
2892 * @ctxt: the XPath Parser context
2893 *
2894 * Implement the ceiling() XPath function
2895 * The ceiling function returns the smallest (closest to negative infinity)
2896 * number that is not less than the argument and that is an integer.
2897 */
2898void
2899xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002900 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002901
2902 CHECK_ARITY(1);
2903 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002904 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002905 if (f != ctxt->value->floatval)
2906 ctxt->value->floatval = f + 1;
2907}
2908
2909/**
2910 * xmlXPathRoundFunction:
2911 * @ctxt: the XPath Parser context
2912 *
2913 * Implement the round() XPath function
2914 * The round function returns the number that is closest to the
2915 * argument and that is an integer. If there are two such numbers,
2916 * then the one that is even is returned.
2917 */
2918void
2919xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002920 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002921
2922 CHECK_ARITY(1);
2923 CHECK_TYPE(XPATH_NUMBER);
2924 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002925 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002926 if (ctxt->value->floatval < f + 0.5)
2927 ctxt->value->floatval = f;
2928 else if (ctxt->value->floatval == f + 0.5)
2929 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2930 else
2931 ctxt->value->floatval = f + 1;
2932}
2933
2934/************************************************************************
2935 * *
2936 * The Parser *
2937 * *
2938 ************************************************************************/
2939
2940/*
2941 * a couple of forward declarations since we use a recursive call based
2942 * implementation.
2943 */
2944void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2945void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2946void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2947void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2948
2949/**
2950 * xmlXPathParseNCName:
2951 * @ctxt: the XPath Parser context
2952 *
2953 * parse an XML namespace non qualified name.
2954 *
2955 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2956 *
2957 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2958 * CombiningChar | Extender
2959 *
2960 * Returns the namespace name or NULL
2961 */
2962
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002963xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002964xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002965 const xmlChar *q;
2966 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002967
2968 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2969 q = NEXT;
2970
2971 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2972 (CUR == '.') || (CUR == '-') ||
2973 (CUR == '_') ||
2974 (IS_COMBINING(CUR)) ||
2975 (IS_EXTENDER(CUR)))
2976 NEXT;
2977
2978 ret = xmlStrndup(q, CUR_PTR - q);
2979
2980 return(ret);
2981}
2982
2983/**
2984 * xmlXPathParseQName:
2985 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002986 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002987 *
2988 * parse an XML qualified name
2989 *
2990 * [NS 5] QName ::= (Prefix ':')? LocalPart
2991 *
2992 * [NS 6] Prefix ::= NCName
2993 *
2994 * [NS 7] LocalPart ::= NCName
2995 *
2996 * Returns the function returns the local part, and prefix is updated
2997 * to get the Prefix if any.
2998 */
2999
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003000xmlChar *
3001xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3002 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003003
3004 *prefix = NULL;
3005 ret = xmlXPathParseNCName(ctxt);
3006 if (CUR == ':') {
3007 *prefix = ret;
3008 NEXT;
3009 ret = xmlXPathParseNCName(ctxt);
3010 }
3011 return(ret);
3012}
3013
3014/**
3015 * xmlXPathStringEvalNumber:
3016 * @str: A string to scan
3017 *
3018 * [30] Number ::= Digits ('.' Digits)?
3019 * | '.' Digits
3020 * [31] Digits ::= [0-9]+
3021 *
3022 * Parse and evaluate a Number in the string
3023 *
3024 * BUG: "1.' is not valid ... James promised correction
3025 * as Digits ('.' Digits?)?
3026 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003027 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003028 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003029double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003030xmlXPathStringEvalNumber(const xmlChar *str) {
3031 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003032 double ret = 0.0;
3033 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003034 int ok = 0;
3035
3036 while (*cur == ' ') cur++;
3037 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003038 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003039 }
3040 while ((*cur >= '0') && (*cur <= '9')) {
3041 ret = ret * 10 + (*cur - '0');
3042 ok = 1;
3043 cur++;
3044 }
3045 if (*cur == '.') {
3046 cur++;
3047 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003048 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003049 }
3050 while ((*cur >= '0') && (*cur <= '9')) {
3051 mult /= 10;
3052 ret = ret + (*cur - '0') * mult;
3053 cur++;
3054 }
3055 }
3056 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003057 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003058 return(ret);
3059}
3060
3061/**
3062 * xmlXPathEvalNumber:
3063 * @ctxt: the XPath Parser context
3064 *
3065 * [30] Number ::= Digits ('.' Digits)?
3066 * | '.' Digits
3067 * [31] Digits ::= [0-9]+
3068 *
3069 * Parse and evaluate a Number, then push it on the stack
3070 *
3071 * BUG: "1.' is not valid ... James promised correction
3072 * as Digits ('.' Digits?)?
3073 */
3074void
3075xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003076 double ret = 0.0;
3077 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003078 int ok = 0;
3079
3080 CHECK_ERROR;
3081 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3082 ERROR(XPATH_NUMBER_ERROR);
3083 }
3084 while ((CUR >= '0') && (CUR <= '9')) {
3085 ret = ret * 10 + (CUR - '0');
3086 ok = 1;
3087 NEXT;
3088 }
3089 if (CUR == '.') {
3090 NEXT;
3091 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3092 ERROR(XPATH_NUMBER_ERROR);
3093 }
3094 while ((CUR >= '0') && (CUR <= '9')) {
3095 mult /= 10;
3096 ret = ret + (CUR - '0') * mult;
3097 NEXT;
3098 }
3099 }
3100 valuePush(ctxt, xmlXPathNewFloat(ret));
3101}
3102
3103/**
3104 * xmlXPathEvalLiteral:
3105 * @ctxt: the XPath Parser context
3106 *
3107 * Parse a Literal and push it on the stack.
3108 *
3109 * [29] Literal ::= '"' [^"]* '"'
3110 * | "'" [^']* "'"
3111 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003112 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003113 */
3114void
3115xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003116 const xmlChar *q;
3117 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003118
3119 if (CUR == '"') {
3120 NEXT;
3121 q = CUR_PTR;
3122 while ((IS_CHAR(CUR)) && (CUR != '"'))
3123 NEXT;
3124 if (!IS_CHAR(CUR)) {
3125 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3126 } else {
3127 ret = xmlStrndup(q, CUR_PTR - q);
3128 NEXT;
3129 }
3130 } else if (CUR == '\'') {
3131 NEXT;
3132 q = CUR_PTR;
3133 while ((IS_CHAR(CUR)) && (CUR != '\''))
3134 NEXT;
3135 if (!IS_CHAR(CUR)) {
3136 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3137 } else {
3138 ret = xmlStrndup(q, CUR_PTR - q);
3139 NEXT;
3140 }
3141 } else {
3142 ERROR(XPATH_START_LITERAL_ERROR);
3143 }
3144 if (ret == NULL) return;
3145 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003146 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003147}
3148
3149/**
3150 * xmlXPathEvalVariableReference:
3151 * @ctxt: the XPath Parser context
3152 *
3153 * Parse a VariableReference, evaluate it and push it on the stack.
3154 *
3155 * The variable bindings consist of a mapping from variable names
3156 * to variable values. The value of a variable is an object, which
3157 * of any of the types that are possible for the value of an expression,
3158 * and may also be of additional types not specified here.
3159 *
3160 * Early evaluation is possible since:
3161 * The variable bindings [...] used to evaluate a subexpression are
3162 * always the same as those used to evaluate the containing expression.
3163 *
3164 * [36] VariableReference ::= '$' QName
3165 */
3166void
3167xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003168 xmlChar *name;
3169 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003170 xmlXPathObjectPtr value;
3171
3172 if (CUR != '$') {
3173 ERROR(XPATH_VARIABLE_REF_ERROR);
3174 }
3175 name = xmlXPathParseQName(ctxt, &prefix);
3176 if (name == NULL) {
3177 ERROR(XPATH_VARIABLE_REF_ERROR);
3178 }
3179 value = xmlXPathVariablelookup(ctxt, prefix, name);
3180 if (value == NULL) {
3181 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3182 }
3183 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003184 if (prefix != NULL) xmlFree(prefix);
3185 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003186}
3187
3188
3189/**
3190 * xmlXPathFunctionLookup:
3191 * @ctxt: the XPath Parser context
3192 * @name: a name string
3193 *
3194 * Search for a function of the given name
3195 *
3196 * [35] FunctionName ::= QName - NodeType
3197 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003198 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003199 *
3200 * Returns the xmlXPathFunction if found, or NULL otherwise
3201 */
3202xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003203xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003204 switch (name[0]) {
3205 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003206 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003207 return(xmlXPathBooleanFunction);
3208 break;
3209 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003210 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003211 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003212 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003213 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003214 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003215 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003216 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003217 return(xmlXPathContainsFunction);
3218 break;
3219 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003220 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003221 return(xmlXPathIdFunction);
3222 break;
3223 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003224 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003225 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003226 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003227 return(xmlXPathFloorFunction);
3228 break;
3229 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003230 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003231 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003232 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003233 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003234 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003235 return(xmlXPathLocalPartFunction);
3236 break;
3237 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003238 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003239 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003240 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003241 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003242 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003243 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003244 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3245 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003246 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003247 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003248 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003249 return(xmlXPathNumberFunction);
3250 break;
3251 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003252 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003253 return(xmlXPathPositionFunction);
3254 break;
3255 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003256 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003257 return(xmlXPathRoundFunction);
3258 break;
3259 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003260 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003261 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003262 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003263 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003264 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003265 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003266 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003267 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003268 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003269 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003270 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003271 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003272 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003273 return(xmlXPathSumFunction);
3274 break;
3275 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003276 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003277 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003278 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003279 return(xmlXPathTranslateFunction);
3280 break;
3281 }
3282 return(NULL);
3283}
3284
3285/**
3286 * xmlXPathEvalLocationPathName:
3287 * @ctxt: the XPath Parser context
3288 * @name: a name string
3289 *
3290 * Various names in the beginning of a LocationPath expression
3291 * indicate whether that's an Axis, a node type,
3292 *
3293 * [6] AxisName ::= 'ancestor'
3294 * | 'ancestor-or-self'
3295 * | 'attribute'
3296 * | 'child'
3297 * | 'descendant'
3298 * | 'descendant-or-self'
3299 * | 'following'
3300 * | 'following-sibling'
3301 * | 'namespace'
3302 * | 'parent'
3303 * | 'preceding'
3304 * | 'preceding-sibling'
3305 * | 'self'
3306 * [38] NodeType ::= 'comment'
3307 * | 'text'
3308 * | 'processing-instruction'
3309 * | 'node'
3310 */
3311int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003312xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003313 switch (name[0]) {
3314 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003315 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3316 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3317 return(AXIS_ANCESTOR_OR_SELF);
3318 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003319 break;
3320 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003321 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3322 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003323 break;
3324 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003325 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3326 return(AXIS_DESCENDANT);
3327 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3328 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003329 break;
3330 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003331 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3332 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3333 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003334 break;
3335 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003336 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3337 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003338 break;
3339 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003340 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3341 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3342 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3343 return(AXIS_PRECEDING_SIBLING);
3344 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3345 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 break;
3347 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003348 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003349 break;
3350 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003351 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003352 break;
3353 }
3354 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3355 return(0);
3356}
3357
3358/**
3359 * xmlXPathEvalFunctionCall:
3360 * @ctxt: the XPath Parser context
3361 *
3362 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3363 * [17] Argument ::= Expr
3364 *
3365 * Parse and evaluate a function call, the evaluation of all arguments are
3366 * pushed on the stack
3367 */
3368void
3369xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003370 xmlChar *name;
3371 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003372 xmlXPathFunction func;
3373 int nbargs = 0;
3374
3375 name = xmlXPathParseQName(ctxt, &prefix);
3376 if (name == NULL) {
3377 ERROR(XPATH_EXPR_ERROR);
3378 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003379 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003380 func = xmlXPathIsFunction(ctxt, name);
3381 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003382 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003383 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3384 }
3385#ifdef DEBUG_EXPR
3386 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3387#endif
3388
3389 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003390 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003391 ERROR(XPATH_EXPR_ERROR);
3392 }
3393 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003394 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003395
3396 while (CUR != ')') {
3397 xmlXPathEvalExpr(ctxt);
3398 nbargs++;
3399 if (CUR == ')') break;
3400 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003401 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003402 ERROR(XPATH_EXPR_ERROR);
3403 }
3404 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003405 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003406 }
3407 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003408 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003409 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003410 func(ctxt, nbargs);
3411}
3412
3413/**
3414 * xmlXPathEvalPrimaryExpr:
3415 * @ctxt: the XPath Parser context
3416 *
3417 * [15] PrimaryExpr ::= VariableReference
3418 * | '(' Expr ')'
3419 * | Literal
3420 * | Number
3421 * | FunctionCall
3422 *
3423 * Parse and evaluate a primary expression, then push the result on the stack
3424 */
3425void
3426xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003427 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003428 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3429 else if (CUR == '(') {
3430 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003431 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003432 xmlXPathEvalExpr(ctxt);
3433 if (CUR != ')') {
3434 ERROR(XPATH_EXPR_ERROR);
3435 }
3436 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003437 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003438 } else if (IS_DIGIT(CUR)) {
3439 xmlXPathEvalNumber(ctxt);
3440 } else if ((CUR == '\'') || (CUR == '"')) {
3441 xmlXPathEvalLiteral(ctxt);
3442 } else {
3443 xmlXPathEvalFunctionCall(ctxt);
3444 }
3445}
3446
3447/**
3448 * xmlXPathEvalFilterExpr:
3449 * @ctxt: the XPath Parser context
3450 *
3451 * [20] FilterExpr ::= PrimaryExpr
3452 * | FilterExpr Predicate
3453 *
3454 * Parse and evaluate a filter expression, then push the result on the stack
3455 * Square brackets are used to filter expressions in the same way that
3456 * they are used in location paths. It is an error if the expression to
3457 * be filtered does not evaluate to a node-set. The context node list
3458 * used for evaluating the expression in square brackets is the node-set
3459 * to be filtered listed in document order.
3460 */
3461
3462void
3463xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3464 /****
3465 xmlNodeSetPtr oldset = NULL;
3466 xmlXPathObjectPtr arg;
3467 ****/
3468
3469 xmlXPathEvalPrimaryExpr(ctxt);
3470 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003471 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003472
3473 if (CUR != '[') return;
3474
3475 CHECK_TYPE(XPATH_NODESET);
3476
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003477 while (CUR == '[') {
3478 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003479 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003480 }
3481
3482
3483}
3484
3485/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003486 * xmlXPathScanName:
3487 * @ctxt: the XPath Parser context
3488 *
3489 * Trickery: parse an XML name but without consuming the input flow
3490 * Needed for rollback cases.
3491 *
3492 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3493 * CombiningChar | Extender
3494 *
3495 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3496 *
3497 * [6] Names ::= Name (S Name)*
3498 *
3499 * Returns the Name parsed or NULL
3500 */
3501
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003502xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003503xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003504 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003505 int len = 0;
3506
Daniel Veillard00fdf371999-10-08 09:40:39 +00003507 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003508 if (!IS_LETTER(CUR) && (CUR != '_') &&
3509 (CUR != ':')) {
3510 return(NULL);
3511 }
3512
3513 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3514 (NXT(len) == '.') || (NXT(len) == '-') ||
3515 (NXT(len) == '_') || (NXT(len) == ':') ||
3516 (IS_COMBINING(NXT(len))) ||
3517 (IS_EXTENDER(NXT(len)))) {
3518 buf[len] = NXT(len);
3519 len++;
3520 if (len >= XML_MAX_NAMELEN) {
3521 fprintf(stderr,
3522 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3523 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3524 (NXT(len) == '.') || (NXT(len) == '-') ||
3525 (NXT(len) == '_') || (NXT(len) == ':') ||
3526 (IS_COMBINING(NXT(len))) ||
3527 (IS_EXTENDER(NXT(len))))
3528 len++;
3529 break;
3530 }
3531 }
3532 return(xmlStrndup(buf, len));
3533}
3534
3535/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003536 * xmlXPathEvalPathExpr:
3537 * @ctxt: the XPath Parser context
3538 *
3539 * [19] PathExpr ::= LocationPath
3540 * | FilterExpr
3541 * | FilterExpr '/' RelativeLocationPath
3542 * | FilterExpr '//' RelativeLocationPath
3543 *
3544 * Parse and evaluate a path expression, then push the result on the stack
3545 * The / operator and // operators combine an arbitrary expression
3546 * and a relative location path. It is an error if the expression
3547 * does not evaluate to a node-set.
3548 * The / operator does composition in the same way as when / is
3549 * used in a location path. As in location paths, // is short for
3550 * /descendant-or-self::node()/.
3551 */
3552
3553void
3554xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3555 xmlNodeSetPtr newset = NULL;
3556
Daniel Veillard00fdf371999-10-08 09:40:39 +00003557 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003558 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3559 (CUR == '\'') || (CUR == '"')) {
3560 xmlXPathEvalFilterExpr(ctxt);
3561 CHECK_ERROR;
3562 if ((CUR == '/') && (NXT(1) == '/')) {
3563 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003564 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003565 if (ctxt->context->nodelist == NULL) {
3566 STRANGE
3567 xmlXPathRoot(ctxt);
3568 }
3569 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3570 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3571 if (ctxt->context->nodelist != NULL)
3572 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3573 ctxt->context->nodelist = newset;
3574 ctxt->context->node = NULL;
3575 xmlXPathEvalRelativeLocationPath(ctxt);
3576 } else if (CUR == '/') {
3577 xmlXPathEvalRelativeLocationPath(ctxt);
3578 }
3579 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003580 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003581 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003582
3583 name = xmlXPathScanName(ctxt);
3584 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3585 xmlXPathEvalLocationPath(ctxt);
3586 else
3587 xmlXPathEvalFilterExpr(ctxt);
3588 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003589 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003590 }
3591}
3592
3593/**
3594 * xmlXPathEvalUnionExpr:
3595 * @ctxt: the XPath Parser context
3596 *
3597 * [18] UnionExpr ::= PathExpr
3598 * | UnionExpr '|' PathExpr
3599 *
3600 * Parse and evaluate an union expression, then push the result on the stack
3601 */
3602
3603void
3604xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3605 xmlXPathEvalPathExpr(ctxt);
3606 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003607 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003608 if (CUR == '|') {
3609 xmlNodeSetPtr old = ctxt->context->nodelist;
3610
Daniel Veillard00fdf371999-10-08 09:40:39 +00003611 NEXT;
3612 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003613 xmlXPathEvalPathExpr(ctxt);
3614
3615 if (ctxt->context->nodelist == NULL)
3616 ctxt->context->nodelist = old;
3617 else {
3618 ctxt->context->nodelist =
3619 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3620 xmlXPathFreeNodeSet(old);
3621 }
3622 }
3623}
3624
3625/**
3626 * xmlXPathEvalUnaryExpr:
3627 * @ctxt: the XPath Parser context
3628 *
3629 * [27] UnaryExpr ::= UnionExpr
3630 * | '-' UnaryExpr
3631 *
3632 * Parse and evaluate an unary expression, then push the result on the stack
3633 */
3634
3635void
3636xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3637 int minus = 0;
3638
Daniel Veillard00fdf371999-10-08 09:40:39 +00003639 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003640 if (CUR == '-') {
3641 minus = 1;
3642 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003643 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003644 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003645 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003646 CHECK_ERROR;
3647 if (minus) {
3648 xmlXPathValueFlipSign(ctxt);
3649 }
3650}
3651
3652/**
3653 * xmlXPathEvalMultiplicativeExpr:
3654 * @ctxt: the XPath Parser context
3655 *
3656 * [26] MultiplicativeExpr ::= UnaryExpr
3657 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3658 * | MultiplicativeExpr 'div' UnaryExpr
3659 * | MultiplicativeExpr 'mod' UnaryExpr
3660 * [34] MultiplyOperator ::= '*'
3661 *
3662 * Parse and evaluate an Additive expression, then push the result on the stack
3663 */
3664
3665void
3666xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3667 xmlXPathEvalUnaryExpr(ctxt);
3668 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003669 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003670 while ((CUR == '*') ||
3671 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3672 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3673 int op = -1;
3674
3675 if (CUR == '*') {
3676 op = 0;
3677 NEXT;
3678 } else if (CUR == 'd') {
3679 op = 1;
3680 SKIP(3);
3681 } else if (CUR == 'm') {
3682 op = 2;
3683 SKIP(3);
3684 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003685 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003686 xmlXPathEvalUnaryExpr(ctxt);
3687 CHECK_ERROR;
3688 switch (op) {
3689 case 0:
3690 xmlXPathMultValues(ctxt);
3691 break;
3692 case 1:
3693 xmlXPathDivValues(ctxt);
3694 break;
3695 case 2:
3696 xmlXPathModValues(ctxt);
3697 break;
3698 }
3699 }
3700}
3701
3702/**
3703 * xmlXPathEvalAdditiveExpr:
3704 * @ctxt: the XPath Parser context
3705 *
3706 * [25] AdditiveExpr ::= MultiplicativeExpr
3707 * | AdditiveExpr '+' MultiplicativeExpr
3708 * | AdditiveExpr '-' MultiplicativeExpr
3709 *
3710 * Parse and evaluate an Additive expression, then push the result on the stack
3711 */
3712
3713void
3714xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3715 xmlXPathEvalMultiplicativeExpr(ctxt);
3716 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003717 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003718 while ((CUR == '+') || (CUR == '-')) {
3719 int plus;
3720
3721 if (CUR == '+') plus = 1;
3722 else plus = 0;
3723 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003724 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003725 xmlXPathEvalMultiplicativeExpr(ctxt);
3726 CHECK_ERROR;
3727 if (plus) xmlXPathAddValues(ctxt);
3728 else xmlXPathSubValues(ctxt);
3729 }
3730}
3731
3732/**
3733 * xmlXPathEvalRelationalExpr:
3734 * @ctxt: the XPath Parser context
3735 *
3736 * [24] RelationalExpr ::= AdditiveExpr
3737 * | RelationalExpr '<' AdditiveExpr
3738 * | RelationalExpr '>' AdditiveExpr
3739 * | RelationalExpr '<=' AdditiveExpr
3740 * | RelationalExpr '>=' AdditiveExpr
3741 *
3742 * A <= B > C is allowed ? Answer from James, yes with
3743 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3744 * which is basically what got implemented.
3745 *
3746 * Parse and evaluate a Relational expression, then push the result
3747 * on the stack
3748 */
3749
3750void
3751xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3752 xmlXPathEvalAdditiveExpr(ctxt);
3753 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003754 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003755 while ((CUR == '<') ||
3756 (CUR == '>') ||
3757 ((CUR == '<') && (NXT(1) == '=')) ||
3758 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003759 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003760
3761 if (CUR == '<') inf = 1;
3762 else inf = 0;
3763 if (NXT(1) == '=') strict = 0;
3764 else strict = 1;
3765 NEXT;
3766 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003767 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003768 xmlXPathEvalAdditiveExpr(ctxt);
3769 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003770 ret = xmlXPathCompareValues(ctxt, inf, strict);
3771 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003772 }
3773}
3774
3775/**
3776 * xmlXPathEvalEqualityExpr:
3777 * @ctxt: the XPath Parser context
3778 *
3779 * [23] EqualityExpr ::= RelationalExpr
3780 * | EqualityExpr '=' RelationalExpr
3781 * | EqualityExpr '!=' RelationalExpr
3782 *
3783 * A != B != C is allowed ? Answer from James, yes with
3784 * (RelationalExpr = RelationalExpr) = RelationalExpr
3785 * (RelationalExpr != RelationalExpr) != RelationalExpr
3786 * which is basically what got implemented.
3787 *
3788 * Parse and evaluate an Equality expression, then push the result on the stack
3789 *
3790 */
3791void
3792xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3793 xmlXPathEvalRelationalExpr(ctxt);
3794 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003795 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003796 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003797 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003798 int eq, equal;
3799
3800 if (CUR == '=') eq = 1;
3801 else eq = 0;
3802 NEXT;
3803 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003804 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003805 xmlXPathEvalRelationalExpr(ctxt);
3806 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003807 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003808 if (eq) res = xmlXPathNewBoolean(equal);
3809 else res = xmlXPathNewBoolean(!equal);
3810 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003811 }
3812}
3813
3814/**
3815 * xmlXPathEvalAndExpr:
3816 * @ctxt: the XPath Parser context
3817 *
3818 * [22] AndExpr ::= EqualityExpr
3819 * | AndExpr 'and' EqualityExpr
3820 *
3821 * Parse and evaluate an AND expression, then push the result on the stack
3822 *
3823 */
3824void
3825xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3826 xmlXPathEvalEqualityExpr(ctxt);
3827 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003828 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003829 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3830 xmlXPathObjectPtr arg1, arg2;
3831
3832 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003833 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003834 xmlXPathEvalEqualityExpr(ctxt);
3835 CHECK_ERROR;
3836 arg2 = valuePop(ctxt);
3837 arg1 = valuePop(ctxt);
3838 arg1->boolval &= arg2->boolval;
3839 valuePush(ctxt, arg1);
3840 xmlXPathFreeObject(arg2);
3841 }
3842}
3843
3844/**
3845 * xmlXPathEvalExpr:
3846 * @ctxt: the XPath Parser context
3847 *
3848 * [14] Expr ::= OrExpr
3849 * [21] OrExpr ::= AndExpr
3850 * | OrExpr 'or' AndExpr
3851 *
3852 * Parse and evaluate an expression, then push the result on the stack
3853 *
3854 */
3855void
3856xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3857 xmlXPathEvalAndExpr(ctxt);
3858 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003859 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003860 while ((CUR == 'o') && (NXT(1) == 'r')) {
3861 xmlXPathObjectPtr arg1, arg2;
3862
3863 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003864 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003865 xmlXPathEvalAndExpr(ctxt);
3866 CHECK_ERROR;
3867 arg2 = valuePop(ctxt);
3868 arg1 = valuePop(ctxt);
3869 arg1->boolval |= arg2->boolval;
3870 valuePush(ctxt, arg1);
3871 xmlXPathFreeObject(arg2);
3872 }
3873}
3874
3875/**
3876 * xmlXPathEvaluatePredicateResult:
3877 * @ctxt: the XPath Parser context
3878 * @res: the Predicate Expression evaluation result
3879 * @index: index of the current node in the current list
3880 *
3881 * Evaluate a predicate result for the current node.
3882 * A PredicateExpr is evaluated by evaluating the Expr and converting
3883 * the result to a boolean. If the result is a number, the result will
3884 * be converted to true if the number is equal to the position of the
3885 * context node in the context node list (as returned by the position
3886 * function) and will be converted to false otherwise; if the result
3887 * is not a number, then the result will be converted as if by a call
3888 * to the boolean function.
3889 */
3890int
3891xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3892 xmlXPathObjectPtr res, int index) {
3893 if (res == NULL) return(0);
3894 switch (res->type) {
3895 case XPATH_BOOLEAN:
3896 return(res->boolval);
3897 case XPATH_NUMBER:
3898 return(res->floatval == index);
3899 case XPATH_NODESET:
3900 return(res->nodesetval->nodeNr != 0);
3901 case XPATH_STRING:
3902 return((res->stringval != NULL) &&
3903 (xmlStrlen(res->stringval) != 0));
3904 default:
3905 STRANGE
3906 }
3907 return(0);
3908}
3909
3910/**
3911 * xmlXPathEvalPredicate:
3912 * @ctxt: the XPath Parser context
3913 *
3914 * [8] Predicate ::= '[' PredicateExpr ']'
3915 * [9] PredicateExpr ::= Expr
3916 *
3917 * Parse and evaluate a predicate for all the elements of the
3918 * current node list. Then refine the list by removing all
3919 * nodes where the predicate is false.
3920 */
3921void
3922xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003923 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003924 xmlXPathObjectPtr res;
3925 xmlNodeSetPtr newset = NULL;
3926 int i;
3927
Daniel Veillard00fdf371999-10-08 09:40:39 +00003928 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003929 if (CUR != '[') {
3930 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3931 }
3932 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003933 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003934 if ((ctxt->context->nodelist == NULL) ||
3935 (ctxt->context->nodelist->nodeNr == 0)) {
3936 ctxt->context->node = NULL;
3937 xmlXPathEvalExpr(ctxt);
3938 CHECK_ERROR;
3939 res = valuePop(ctxt);
3940 if (res != NULL)
3941 xmlXPathFreeObject(res);
3942 } else {
3943 cur = ctxt->cur;
3944 newset = xmlXPathNodeSetCreate(NULL);
3945 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3946 ctxt->cur = cur;
3947 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3948 xmlXPathEvalExpr(ctxt);
3949 CHECK_ERROR;
3950 res = valuePop(ctxt);
3951 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3952 xmlXPathNodeSetAdd(newset,
3953 ctxt->context->nodelist->nodeTab[i]);
3954 if (res != NULL)
3955 xmlXPathFreeObject(res);
3956 }
3957 if (ctxt->context->nodelist != NULL)
3958 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3959 ctxt->context->nodelist = newset;
3960 ctxt->context->node = NULL;
3961 }
3962 if (CUR != ']') {
3963 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3964 }
3965 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003966 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003967#ifdef DEBUG_STEP
3968 fprintf(xmlXPathDebug, "After predicate : ");
3969 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3970#endif
3971}
3972
3973/**
3974 * xmlXPathEvalBasis:
3975 * @ctxt: the XPath Parser context
3976 *
3977 * [5] Basis ::= AxisName '::' NodeTest
3978 * | AbbreviatedBasis
3979 * [13] AbbreviatedBasis ::= NodeTest
3980 * | '@' NodeTest
3981 * [7] NodeTest ::= WildcardName
3982 * | NodeType '(' ')'
3983 * | 'processing-instruction' '(' Literal ')'
3984 * [37] WildcardName ::= '*'
3985 * | NCName ':' '*'
3986 * | QName
3987 *
3988 * Evaluate one step in a Location Path
3989 */
3990void
3991xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003992 xmlChar *name = NULL;
3993 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003994 int type = 0;
3995 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
3996 int nodetest = NODE_TEST_NONE;
3997 int nodetype = 0;
3998 xmlNodeSetPtr newset = NULL;
3999
4000 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004001 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004002 axis = AXIS_ATTRIBUTE;
4003 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004004 } else if (CUR == '*') {
4005 NEXT;
4006 nodetest = NODE_TEST_ALL;
4007 } else {
4008 name = xmlXPathParseNCName(ctxt);
4009 if (name == NULL) {
4010 ERROR(XPATH_EXPR_ERROR);
4011 }
4012 type = xmlXPathGetNameType(ctxt, name);
4013 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004014 case IS_FUNCTION: {
4015 xmlXPathFunction func;
4016 int nbargs = 0;
4017 xmlXPathObjectPtr top;
4018
4019 top = ctxt->value;
4020 func = xmlXPathIsFunction(ctxt, name);
4021 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004022 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004023 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4024 }
4025#ifdef DEBUG_EXPR
4026 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4027#endif
4028
4029 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004030 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004031 ERROR(XPATH_EXPR_ERROR);
4032 }
4033 NEXT;
4034
4035 while (CUR != ')') {
4036 xmlXPathEvalExpr(ctxt);
4037 nbargs++;
4038 if (CUR == ')') break;
4039 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004040 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004041 ERROR(XPATH_EXPR_ERROR);
4042 }
4043 NEXT;
4044 }
4045 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004046 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004047 func(ctxt, nbargs);
4048 if ((ctxt->value != top) &&
4049 (ctxt->value != NULL) &&
4050 (ctxt->value->type == XPATH_NODESET)) {
4051 xmlXPathObjectPtr cur;
4052
4053 cur = valuePop(ctxt);
4054 ctxt->context->nodelist = cur->nodesetval;
4055 ctxt->context->node = NULL;
4056 cur->nodesetval = NULL;
4057 xmlXPathFreeObject(cur);
4058 }
4059 return;
4060 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004061 /*
4062 * Simple case: no axis seach all given node types.
4063 */
4064 case NODE_TYPE_COMMENT:
4065 if ((CUR != '(') || (NXT(1) != ')')) break;
4066 SKIP(2);
4067 nodetest = NODE_TEST_TYPE;
4068 nodetype = XML_COMMENT_NODE;
4069 goto search_nodes;
4070 case NODE_TYPE_TEXT:
4071 if ((CUR != '(') || (NXT(1) != ')')) break;
4072 SKIP(2);
4073 nodetest = NODE_TEST_TYPE;
4074 nodetype = XML_TEXT_NODE;
4075 goto search_nodes;
4076 case NODE_TYPE_NODE:
4077 if ((CUR != '(') || (NXT(1) != ')')) {
4078 nodetest = NODE_TEST_NAME;
4079 break;
4080 }
4081 SKIP(2);
4082 nodetest = NODE_TEST_TYPE;
4083 nodetype = XML_ELEMENT_NODE;
4084 goto search_nodes;
4085 case NODE_TYPE_PI:
4086 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004087 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004088 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004089 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004090 xmlXPathObjectPtr cur;
4091
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004092 /*
4093 * Specific case: search a PI by name.
4094 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004095 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004096 nodetest = NODE_TEST_PI;
4097 xmlXPathEvalLiteral(ctxt);
4098 CHECK_ERROR;
4099 if (CUR != ')')
4100 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004101 NEXT;
4102 xmlXPathStringFunction(ctxt, 1);
4103 CHECK_ERROR;
4104 cur = valuePop(ctxt);
4105 name = xmlStrdup(cur->stringval);
4106 xmlXPathFreeObject(cur);
4107 } else
4108 SKIP(2);
4109 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004110 goto search_nodes;
4111
4112 /*
4113 * Handling of the compund form: got the axis.
4114 */
4115 case AXIS_ANCESTOR:
4116 case AXIS_ANCESTOR_OR_SELF:
4117 case AXIS_ATTRIBUTE:
4118 case AXIS_CHILD:
4119 case AXIS_DESCENDANT:
4120 case AXIS_DESCENDANT_OR_SELF:
4121 case AXIS_FOLLOWING:
4122 case AXIS_FOLLOWING_SIBLING:
4123 case AXIS_NAMESPACE:
4124 case AXIS_PARENT:
4125 case AXIS_PRECEDING:
4126 case AXIS_PRECEDING_SIBLING:
4127 case AXIS_SELF:
4128 if ((CUR != ':') || (NXT(1) != ':')) {
4129 nodetest = NODE_TEST_NAME;
4130 break;
4131 }
4132 SKIP(2);
4133 axis = type;
4134 break;
4135
4136 /*
4137 * Default: abbreviated syntax the axis is AXIS_CHILD
4138 */
4139 default:
4140 nodetest = NODE_TEST_NAME;
4141 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004142parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004143 if (nodetest == NODE_TEST_NONE) {
4144 if (CUR == '*') {
4145 NEXT;
4146 nodetest = NODE_TEST_ALL;
4147 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004148 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004149 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004150 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004151 if (name == NULL) {
4152 ERROR(XPATH_EXPR_ERROR);
4153 }
4154 type = xmlXPathGetNameType(ctxt, name);
4155 switch (type) {
4156 /*
4157 * Simple case: no axis seach all given node types.
4158 */
4159 case NODE_TYPE_COMMENT:
4160 if ((CUR != '(') || (NXT(1) != ')')) break;
4161 SKIP(2);
4162 nodetest = NODE_TEST_TYPE;
4163 nodetype = XML_COMMENT_NODE;
4164 goto search_nodes;
4165 case NODE_TYPE_TEXT:
4166 if ((CUR != '(') || (NXT(1) != ')')) break;
4167 SKIP(2);
4168 nodetest = NODE_TEST_TYPE;
4169 nodetype = XML_TEXT_NODE;
4170 goto search_nodes;
4171 case NODE_TYPE_NODE:
4172 if ((CUR != '(') || (NXT(1) != ')')) {
4173 nodetest = NODE_TEST_NAME;
4174 break;
4175 }
4176 SKIP(2);
4177 nodetest = NODE_TEST_TYPE;
4178 nodetype = XML_ELEMENT_NODE;
4179 goto search_nodes;
4180 case NODE_TYPE_PI:
4181 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004182 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004183 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004184 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004185 xmlXPathObjectPtr cur;
4186
Daniel Veillardb05deb71999-08-10 19:04:08 +00004187 /*
4188 * Specific case: search a PI by name.
4189 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004190 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004191 nodetest = NODE_TEST_PI;
4192 xmlXPathEvalLiteral(ctxt);
4193 CHECK_ERROR;
4194 if (CUR != ')')
4195 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004196 NEXT;
4197 xmlXPathStringFunction(ctxt, 1);
4198 CHECK_ERROR;
4199 cur = valuePop(ctxt);
4200 name = xmlStrdup(cur->stringval);
4201 xmlXPathFreeObject(cur);
4202 } else
4203 SKIP(2);
4204 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004205 goto search_nodes;
4206 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004207 nodetest = NODE_TEST_NAME;
4208 }
4209 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4210 NEXT;
4211 prefix = name;
4212 if (CUR == '*') {
4213 NEXT;
4214 nodetest = NODE_TEST_ALL;
4215 } else
4216 name = xmlXPathParseNCName(ctxt);
4217 } else if (name == NULL)
4218 ERROR(XPATH_EXPR_ERROR);
4219 }
4220
4221search_nodes:
4222
4223#ifdef DEBUG_STEP
4224 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4225#endif
4226 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4227 prefix, name);
4228 if (ctxt->context->nodelist != NULL)
4229 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4230 ctxt->context->nodelist = newset;
4231 ctxt->context->node = NULL;
4232#ifdef DEBUG_STEP
4233 fprintf(xmlXPathDebug, "Basis : ");
4234 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4235#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004236 if (name != NULL) xmlFree(name);
4237 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004238}
4239
4240/**
4241 * xmlXPathEvalStep:
4242 * @ctxt: the XPath Parser context
4243 *
4244 * [4] Step ::= Basis Predicate*
4245 * | AbbreviatedStep
4246 * [12] AbbreviatedStep ::= '.'
4247 * | '..'
4248 *
4249 * Evaluate one step in a Location Path
4250 * A location step of . is short for self::node(). This is
4251 * particularly useful in conjunction with //. For example, the
4252 * location path .//para is short for
4253 * self::node()/descendant-or-self::node()/child::para
4254 * and so will select all para descendant elements of the context
4255 * node.
4256 * Similarly, a location step of .. is short for parent::node().
4257 * For example, ../title is short for parent::node()/child::title
4258 * and so will select the title children of the parent of the context
4259 * node.
4260 */
4261void
4262xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4263 xmlNodeSetPtr newset = NULL;
4264
Daniel Veillard00fdf371999-10-08 09:40:39 +00004265 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004266 if ((CUR == '.') && (NXT(1) == '.')) {
4267 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004268 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004269 if (ctxt->context->nodelist == NULL) {
4270 STRANGE
4271 xmlXPathRoot(ctxt);
4272 }
4273 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4274 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4275 if (ctxt->context->nodelist != NULL)
4276 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4277 ctxt->context->nodelist = newset;
4278 ctxt->context->node = NULL;
4279 } else if (CUR == '.') {
4280 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004281 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004282 } else {
4283 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004284 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004285 while (CUR == '[') {
4286 xmlXPathEvalPredicate(ctxt);
4287 }
4288 }
4289#ifdef DEBUG_STEP
4290 fprintf(xmlXPathDebug, "Step : ");
4291 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4292#endif
4293}
4294
4295/**
4296 * xmlXPathEvalRelativeLocationPath:
4297 * @ctxt: the XPath Parser context
4298 *
4299 * [3] RelativeLocationPath ::= Step
4300 * | RelativeLocationPath '/' Step
4301 * | AbbreviatedRelativeLocationPath
4302 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4303 *
4304 */
4305void
4306xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4307 xmlNodeSetPtr newset = NULL;
4308
Daniel Veillard00fdf371999-10-08 09:40:39 +00004309 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004310 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004311 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004312 while (CUR == '/') {
4313 if ((CUR == '/') && (NXT(1) == '/')) {
4314 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004315 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004316 if (ctxt->context->nodelist == NULL) {
4317 STRANGE
4318 xmlXPathRoot(ctxt);
4319 }
4320 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4321 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4322 if (ctxt->context->nodelist != NULL)
4323 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4324 ctxt->context->nodelist = newset;
4325 ctxt->context->node = NULL;
4326 xmlXPathEvalStep(ctxt);
4327 } else if (CUR == '/') {
4328 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004329 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004330 xmlXPathEvalStep(ctxt);
4331 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004332 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004333 }
4334}
4335
4336/**
4337 * xmlXPathEvalLocationPath:
4338 * @ctxt: the XPath Parser context
4339 *
4340 * [1] LocationPath ::= RelativeLocationPath
4341 * | AbsoluteLocationPath
4342 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4343 * | AbbreviatedAbsoluteLocationPath
4344 * [10] AbbreviatedAbsoluteLocationPath ::=
4345 * '//' RelativeLocationPath
4346 *
4347 * // is short for /descendant-or-self::node()/. For example,
4348 * //para is short for /descendant-or-self::node()/child::para and
4349 * so will select any para element in the document (even a para element
4350 * that is a document element will be selected by //para since the
4351 * document element node is a child of the root node); div//para is
4352 * short for div/descendant-or-self::node()/child::para and so will
4353 * select all para descendants of div children.
4354 */
4355void
4356xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4357 xmlNodeSetPtr newset = NULL;
4358
Daniel Veillard00fdf371999-10-08 09:40:39 +00004359 SKIP_BLANKS;
4360 if (CUR != '/') {
4361 xmlXPathEvalRelativeLocationPath(ctxt);
4362 } else {
4363 while (CUR == '/') {
4364 if ((CUR == '/') && (NXT(1) == '/')) {
4365 SKIP(2);
4366 SKIP_BLANKS;
4367 if (ctxt->context->nodelist == NULL)
4368 xmlXPathRoot(ctxt);
4369 newset = xmlXPathNodeCollectAndTest(ctxt,
4370 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4371 XML_ELEMENT_NODE, NULL, NULL);
4372 if (ctxt->context->nodelist != NULL)
4373 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4374 ctxt->context->nodelist = newset;
4375 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004376 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004377 } else if (CUR == '/') {
4378 NEXT;
4379 SKIP_BLANKS;
4380 xmlXPathRoot(ctxt);
4381 if (CUR != 0)
4382 xmlXPathEvalRelativeLocationPath(ctxt);
4383 } else {
4384 xmlXPathEvalRelativeLocationPath(ctxt);
4385 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004386 }
4387 }
4388}
4389
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004390/**
4391 * xmlXPathEval:
4392 * @str: the XPath expression
4393 * @ctxt: the XPath context
4394 *
4395 * Evaluate the XPath Location Path in the given context.
4396 *
4397 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4398 * the caller has to free the object.
4399 */
4400xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004401xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004402 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004403 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004404
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004405 xmlXPathInit();
4406
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004407 CHECK_CONTEXT
4408
4409 if (xmlXPathDebug == NULL)
4410 xmlXPathDebug = stderr;
4411 pctxt = xmlXPathNewParserContext(str, ctxt);
4412 xmlXPathEvalLocationPath(pctxt);
4413
Daniel Veillardb96e6431999-08-29 21:02:19 +00004414 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004415 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004416 tmp = valuePop(pctxt);
4417 if (tmp != NULL);
4418 xmlXPathFreeObject(tmp);
4419 } while (tmp != NULL);
4420 if (res == NULL)
4421 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004422 xmlXPathFreeParserContext(pctxt);
4423 return(res);
4424}
4425
4426/**
4427 * xmlXPathEvalExpression:
4428 * @str: the XPath expression
4429 * @ctxt: the XPath context
4430 *
4431 * Evaluate the XPath expression in the given context.
4432 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004433 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004434 * the caller has to free the object.
4435 */
4436xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004437xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004438 xmlXPathParserContextPtr pctxt;
4439 xmlXPathObjectPtr res, tmp;
4440
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004441 xmlXPathInit();
4442
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004443 CHECK_CONTEXT
4444
4445 if (xmlXPathDebug == NULL)
4446 xmlXPathDebug = stderr;
4447 pctxt = xmlXPathNewParserContext(str, ctxt);
4448 xmlXPathEvalExpr(pctxt);
4449
4450 res = valuePop(pctxt);
4451 do {
4452 tmp = valuePop(pctxt);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004453 if (tmp != NULL);
4454 xmlXPathFreeObject(tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004455 } while (tmp != NULL);
4456 xmlXPathFreeParserContext(pctxt);
4457 return(res);
4458}
4459