blob: 398972f7d9efb8ade5a7c47f98e57812d3942a11 [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer.
5 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#else
19#include "config.h"
20#endif
21
22#include <stdio.h>
23#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000028#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000029#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000030#endif
31#ifdef HAVE_MATH_H
32#include <float.h>
33#endif
34#ifdef HAVE_IEEEFP_H
35#include <ieeefp.h>
36#endif
37#ifdef HAVE_NAN_H
38#include <nan.h>
39#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000040#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000041#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000042#endif
43
Daniel Veillard6454aec1999-09-02 22:04:43 +000044#include "xmlmemory.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000045#include "tree.h"
Daniel Veillardb96e6431999-08-29 21:02:19 +000046#include "valid.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000047#include "xpath.h"
48#include "parserInternals.h"
49
Daniel Veillarddbfd6411999-12-28 16:35:14 +000050/* #define DEBUG */
51/* #define DEBUG_STEP */
52/* #define DEBUG_EXPR */
53
Daniel Veillard1566d3a1999-07-15 14:24:29 +000054/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000055 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000056 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000057 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000058double xmlXPathNAN = 0;
59double xmlXPathPINF = 1;
60double xmlXPathMINF = -1;
61
Daniel Veillardb05deb71999-08-10 19:04:08 +000062#ifndef isinf
63#ifndef HAVE_ISINF
64
65#if HAVE_FPCLASS
66
67int isinf(double d) {
68 fpclass_t type = fpclass(d);
69 switch (type) {
70 case FP_NINF:
71 return(-1);
72 case FP_PINF:
73 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000074 }
75 return(0);
76}
77
78#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
79
80#if HAVE_FP_CLASS_H
81#include <fp_class.h>
82#endif
83
84int isinf(double d) {
85#if HAVE_FP_CLASS
86 int fpclass = fp_class(d);
87#else
88 int fpclass = fp_class_d(d);
89#endif
90 if (fpclass == FP_POS_INF)
91 return(1);
92 if (fpclass == FP_NEG_INF)
93 return(-1);
94 return(0);
95}
96
97#elif defined(HAVE_CLASS)
98
99int isinf(double d) {
100 int fpclass = class(d);
101 if (fpclass == FP_PLUS_INF)
102 return(1);
103 if (fpclass == FP_MINUS_INF)
104 return(-1);
105 return(0);
106}
107#elif defined(finite) || defined(HAVE_FINITE)
108int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000109#elif defined(HUGE_VAL)
110static int isinf(double x)
111{
112 if (x == HUGE_VAL)
113 return(1);
114 if (x == -HUGE_VAL)
115 return(-1);
116 return(0);
117}
118#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000119
120#endif /* ! HAVE_ISINF */
121#endif /* ! defined(isinf) */
122
123#ifndef isnan
124#ifndef HAVE_ISNAN
125
126#ifdef HAVE_ISNAND
127#define isnan(f) isnand(f)
128#endif /* HAVE_iSNAND */
129
130#endif /* ! HAVE_iSNAN */
131#endif /* ! defined(isnan) */
132
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000133/**
134 * xmlXPathInit:
135 *
136 * Initialize the XPath environment
137 */
138void
139xmlXPathInit(void) {
140 static int initialized = 0;
141
142 if (initialized) return;
143
144 xmlXPathNAN = 0;
145 xmlXPathNAN /= 0;
146
147 xmlXPathPINF = 1;
148 xmlXPathPINF /= 0;
149
150 xmlXPathMINF = -1;
151 xmlXPathMINF /= 0;
152
153 initialized = 1;
154}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000155
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000156FILE *xmlXPathDebug = NULL;
157
158#define TODO \
159 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
160 __FILE__, __LINE__);
161
162#define STRANGE \
163 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
164 __FILE__, __LINE__);
165
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000166double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000167void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000168
169/************************************************************************
170 * *
171 * Parser stacks related functions and macros *
172 * *
173 ************************************************************************/
174
175/*
176 * Generic function for accessing stacks in the Parser Context
177 */
178
179#define PUSH_AND_POP(type, name) \
180extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
181 if (ctxt->name##Nr >= ctxt->name##Max) { \
182 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000183 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000184 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
185 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000186 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000187 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000188 } \
189 } \
190 ctxt->name##Tab[ctxt->name##Nr] = value; \
191 ctxt->name = value; \
192 return(ctxt->name##Nr++); \
193} \
194extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
195 type ret; \
196 if (ctxt->name##Nr <= 0) return(0); \
197 ctxt->name##Nr--; \
198 if (ctxt->name##Nr > 0) \
199 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
200 else \
201 ctxt->name = NULL; \
202 ret = ctxt->name##Tab[ctxt->name##Nr]; \
203 ctxt->name##Tab[ctxt->name##Nr] = 0; \
204 return(ret); \
205} \
206
207PUSH_AND_POP(xmlXPathObjectPtr, value)
208
209/*
210 * Macros for accessing the content. Those should be used only by the parser,
211 * and not exported.
212 *
213 * Dirty macros, i.e. one need to make assumption on the context to use them
214 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000215 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000216 * CUR returns the current xmlChar value, i.e. a 8 bit value
217 * in ISO-Latin or UTF-8.
218 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000219 * only to compare to ASCII values otherwise it would break when
220 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000221 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000222 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000223 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000224 * strings within the parser.
225 * CURRENT Returns the current char value, with the full decoding of
226 * UTF-8 if we are using this mode. It returns an int.
227 * NEXT Skip to the next character, this does the proper decoding
228 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000229 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000230 */
231
232#define CUR (*ctxt->cur)
233#define SKIP(val) ctxt->cur += (val)
234#define NXT(val) ctxt->cur[(val)]
235#define CUR_PTR ctxt->cur
236
237#define SKIP_BLANKS \
238 while (IS_BLANK(*(ctxt->cur))) NEXT
239
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000240#define CURRENT (*ctxt->cur)
241#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000242
243/************************************************************************
244 * *
245 * Error handling routines *
246 * *
247 ************************************************************************/
248
249#define XPATH_EXPRESSION_OK 0
250#define XPATH_NUMBER_ERROR 1
251#define XPATH_UNFINISHED_LITERAL_ERROR 2
252#define XPATH_START_LITERAL_ERROR 3
253#define XPATH_VARIABLE_REF_ERROR 4
254#define XPATH_UNDEF_VARIABLE_ERROR 5
255#define XPATH_INVALID_PREDICATE_ERROR 6
256#define XPATH_EXPR_ERROR 7
257#define XPATH_UNCLOSED_ERROR 8
258#define XPATH_UNKNOWN_FUNC_ERROR 9
259#define XPATH_INVALID_OPERAND 10
260#define XPATH_INVALID_TYPE 11
261#define XPATH_INVALID_ARITY 12
262
263const char *xmlXPathErrorMessages[] = {
264 "Ok",
265 "Number encoding",
266 "Unfinished litteral",
267 "Start of litteral",
268 "Expected $ for variable reference",
269 "Undefined variable",
270 "Invalid predicate",
271 "Invalid expression",
272 "Missing closing curly brace",
273 "Unregistered function",
274 "Invalid operand",
275 "Invalid type",
276 "Invalid number of arguments",
277};
278
279/**
280 * xmlXPathError:
281 * @ctxt: the XPath Parser context
282 * @file: the file name
283 * @line: the line number
284 * @no: the error number
285 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000286 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000287 *
288 * Returns the newly created object.
289 */
290void
291xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
292 int line, int no) {
293 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000294 const xmlChar *cur;
295 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000296
297 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
298 xmlXPathErrorMessages[no]);
299
300 cur = ctxt->cur;
301 base = ctxt->base;
302 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
303 cur--;
304 }
305 n = 0;
306 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
307 cur--;
308 if ((*cur == '\n') || (*cur == '\r')) cur++;
309 base = cur;
310 n = 0;
311 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
312 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
313 n++;
314 }
315 fprintf(xmlXPathDebug, "\n");
316 cur = ctxt->cur;
317 while ((*cur == '\n') || (*cur == '\r'))
318 cur--;
319 n = 0;
320 while ((cur != base) && (n++ < 80)) {
321 fprintf(xmlXPathDebug, " ");
322 base++;
323 }
324 fprintf(xmlXPathDebug,"^\n");
325}
326
327#define CHECK_ERROR \
328 if (ctxt->error != XPATH_EXPRESSION_OK) return
329
330#define ERROR(X) \
331 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
332 ctxt->error = (X); return; }
333
Daniel Veillard991e63d1999-08-15 23:32:28 +0000334#define ERROR0(X) \
335 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
336 ctxt->error = (X); return(0); }
337
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000338#define CHECK_TYPE(typeval) \
339 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
340 ERROR(XPATH_INVALID_TYPE) \
341
342
343/************************************************************************
344 * *
345 * Routines to handle NodeSets *
346 * *
347 ************************************************************************/
348
349#define XML_NODESET_DEFAULT 10
350/**
351 * xmlXPathNodeSetCreate:
352 * @val: an initial xmlNodePtr, or NULL
353 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000354 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000355 *
356 * Returns the newly created object.
357 */
358xmlNodeSetPtr
359xmlXPathNodeSetCreate(xmlNodePtr val) {
360 xmlNodeSetPtr ret;
361
Daniel Veillard6454aec1999-09-02 22:04:43 +0000362 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000363 if (ret == NULL) {
364 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
365 return(NULL);
366 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000367 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000368 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000369 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000370 sizeof(xmlNodePtr));
371 if (ret->nodeTab == NULL) {
372 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
373 return(NULL);
374 }
375 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000376 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000377 ret->nodeMax = XML_NODESET_DEFAULT;
378 ret->nodeTab[ret->nodeNr++] = val;
379 }
380 return(ret);
381}
382
383/**
384 * xmlXPathNodeSetAdd:
385 * @cur: the initial node set
386 * @val: a new xmlNodePtr
387 *
388 * add a new xmlNodePtr ot an existing NodeSet
389 */
390void
391xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
392 int i;
393
394 if (val == NULL) return;
395
396 /*
397 * check against doublons
398 */
399 for (i = 0;i < cur->nodeNr;i++)
400 if (cur->nodeTab[i] == val) return;
401
402 /*
403 * grow the nodeTab if needed
404 */
405 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000406 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000407 sizeof(xmlNodePtr));
408 if (cur->nodeTab == NULL) {
409 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
410 return;
411 }
412 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000413 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000414 cur->nodeMax = XML_NODESET_DEFAULT;
415 } else if (cur->nodeNr == cur->nodeMax) {
416 xmlNodePtr *temp;
417
418 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000419 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000420 sizeof(xmlNodePtr));
421 if (temp == NULL) {
422 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
423 return;
424 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000425 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000426 }
427 cur->nodeTab[cur->nodeNr++] = val;
428}
429
430/**
431 * xmlXPathNodeSetMerge:
432 * @val1: the first NodeSet
433 * @val2: the second NodeSet
434 *
435 * Merges two nodesets, all nodes from @val2 are added to @val1
436 *
437 * Returns val1 once extended or NULL in case of error.
438 */
439xmlNodeSetPtr
440xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
441 int i;
442
443 if (val1 == NULL) return(NULL);
444 if (val2 == NULL) return(val1);
445
446 /*
447 * !!!!! this can be optimized a lot, knowing that both
448 * val1 and val2 already have unicity of their values.
449 */
450
451 for (i = 0;i < val2->nodeNr;i++)
452 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
453
454 return(val1);
455}
456
457/**
458 * xmlXPathNodeSetDel:
459 * @cur: the initial node set
460 * @val: an xmlNodePtr
461 *
462 * Removes an xmlNodePtr from an existing NodeSet
463 */
464void
465xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
466 int i;
467
468 if (cur == NULL) return;
469 if (val == NULL) return;
470
471 /*
472 * check against doublons
473 */
474 for (i = 0;i < cur->nodeNr;i++)
475 if (cur->nodeTab[i] == val) break;
476
477 if (i >= cur->nodeNr) {
478#ifdef DEBUG
479 fprintf(xmlXPathDebug,
480 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
481 val->name);
482#endif
483 return;
484 }
485 cur->nodeNr--;
486 for (;i < cur->nodeNr;i++)
487 cur->nodeTab[i] = cur->nodeTab[i + 1];
488 cur->nodeTab[cur->nodeNr] = NULL;
489}
490
491/**
492 * xmlXPathNodeSetRemove:
493 * @cur: the initial node set
494 * @val: the index to remove
495 *
496 * Removes an entry from an existing NodeSet list.
497 */
498void
499xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
500 if (cur == NULL) return;
501 if (val >= cur->nodeNr) return;
502 cur->nodeNr--;
503 for (;val < cur->nodeNr;val++)
504 cur->nodeTab[val] = cur->nodeTab[val + 1];
505 cur->nodeTab[cur->nodeNr] = NULL;
506}
507
508/**
509 * xmlXPathFreeNodeSet:
510 * @obj: the xmlNodeSetPtr to free
511 *
512 * Free the NodeSet compound (not the actual nodes !).
513 */
514void
515xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
516 if (obj == NULL) return;
517 if (obj->nodeTab != NULL) {
518#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000519 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000520#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000521 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000522 }
523#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000524 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000525#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000526 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000527}
528
Daniel Veillardb96e6431999-08-29 21:02:19 +0000529#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000530/**
531 * xmlXPathDebugNodeSet:
532 * @output: a FILE * for the output
533 * @obj: the xmlNodeSetPtr to free
534 *
535 * Quick display of a NodeSet
536 */
537void
538xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
539 int i;
540
541 if (output == NULL) output = xmlXPathDebug;
542 if (obj == NULL) {
543 fprintf(output, "NodeSet == NULL !\n");
544 return;
545 }
546 if (obj->nodeNr == 0) {
547 fprintf(output, "NodeSet is empty\n");
548 return;
549 }
550 if (obj->nodeTab == NULL) {
551 fprintf(output, " nodeTab == NULL !\n");
552 return;
553 }
554 for (i = 0; i < obj->nodeNr; i++) {
555 if (obj->nodeTab[i] == NULL) {
556 fprintf(output, " NULL !\n");
557 return;
558 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000559 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
560 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000561 fprintf(output, " /");
562 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000563 fprintf(output, " noname!");
564 else fprintf(output, " %s", obj->nodeTab[i]->name);
565 }
566 fprintf(output, "\n");
567}
568#endif
569
570/************************************************************************
571 * *
572 * Routines to handle Variable *
573 * *
574 * UNIMPLEMENTED CURRENTLY *
575 * *
576 ************************************************************************/
577
578/**
579 * xmlXPathVariablelookup:
580 * @ctxt: the XPath Parser context
581 * @prefix: the variable name namespace if any
582 * @name: the variable name
583 *
584 * Search in the Variable array of the context for the given
585 * variable value.
586 *
587 * UNIMPLEMENTED: always return NULL.
588 *
589 * Returns the value or NULL if not found
590 */
591xmlXPathObjectPtr
592xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000593 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000594 return(NULL);
595}
596
597/************************************************************************
598 * *
599 * Routines to handle Values *
600 * *
601 ************************************************************************/
602
603/* Allocations are terrible, one need to optimize all this !!! */
604
605/**
606 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000607 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000608 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000609 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000610 *
611 * Returns the newly created object.
612 */
613xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000614xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000615 xmlXPathObjectPtr ret;
616
Daniel Veillard6454aec1999-09-02 22:04:43 +0000617 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000618 if (ret == NULL) {
619 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
620 return(NULL);
621 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000622 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000623 ret->type = XPATH_NUMBER;
624 ret->floatval = val;
625 return(ret);
626}
627
628/**
629 * xmlXPathNewBoolean:
630 * @val: the boolean value
631 *
632 * Create a new xmlXPathObjectPtr of type boolean and of value @val
633 *
634 * Returns the newly created object.
635 */
636xmlXPathObjectPtr
637xmlXPathNewBoolean(int val) {
638 xmlXPathObjectPtr ret;
639
Daniel Veillard6454aec1999-09-02 22:04:43 +0000640 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000641 if (ret == NULL) {
642 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
643 return(NULL);
644 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000645 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000646 ret->type = XPATH_BOOLEAN;
647 ret->boolval = (val != 0);
648 return(ret);
649}
650
651/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000652 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000653 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000654 *
655 * Create a new xmlXPathObjectPtr of type string and of value @val
656 *
657 * Returns the newly created object.
658 */
659xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000660xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000661 xmlXPathObjectPtr ret;
662
Daniel Veillard6454aec1999-09-02 22:04:43 +0000663 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000664 if (ret == NULL) {
665 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
666 return(NULL);
667 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000668 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000669 ret->type = XPATH_STRING;
670 ret->stringval = xmlStrdup(val);
671 return(ret);
672}
673
674/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000675 * xmlXPathNewCString:
676 * @val: the char * value
677 *
678 * Create a new xmlXPathObjectPtr of type string and of value @val
679 *
680 * Returns the newly created object.
681 */
682xmlXPathObjectPtr
683xmlXPathNewCString(const char *val) {
684 xmlXPathObjectPtr ret;
685
Daniel Veillard6454aec1999-09-02 22:04:43 +0000686 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000687 if (ret == NULL) {
688 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
689 return(NULL);
690 }
691 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
692 ret->type = XPATH_STRING;
693 ret->stringval = xmlStrdup(BAD_CAST val);
694 return(ret);
695}
696
697/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000698 * xmlXPathNewNodeSet:
699 * @val: the NodePtr value
700 *
701 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
702 * it with the single Node @val
703 *
704 * Returns the newly created object.
705 */
706xmlXPathObjectPtr
707xmlXPathNewNodeSet(xmlNodePtr val) {
708 xmlXPathObjectPtr ret;
709
Daniel Veillard6454aec1999-09-02 22:04:43 +0000710 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000711 if (ret == NULL) {
712 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
713 return(NULL);
714 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000715 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000716 ret->type = XPATH_NODESET;
717 ret->nodesetval = xmlXPathNodeSetCreate(val);
718 return(ret);
719}
720
721/**
722 * xmlXPathNewNodeSetList:
723 * @val: an existing NodeSet
724 *
725 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
726 * it with the Nodeset @val
727 *
728 * Returns the newly created object.
729 */
730xmlXPathObjectPtr
731xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
732 xmlXPathObjectPtr ret;
733
Daniel Veillard6454aec1999-09-02 22:04:43 +0000734 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000735 if (ret == NULL) {
736 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
737 return(NULL);
738 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000739 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000740 ret->type = XPATH_NODESET;
741 ret->nodesetval = val;
742 return(ret);
743}
744
745/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000746 * xmlXPathFreeNodeSetList:
747 * @obj: an existing NodeSetList object
748 *
749 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
750 * the list contrary to xmlXPathFreeObject().
751 */
752void
753xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
754 if (obj == NULL) return;
755#ifdef DEBUG
756 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
757#endif
758 xmlFree(obj);
759}
760
761/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000762 * xmlXPathFreeObject:
763 * @obj: the object to free
764 *
765 * Free up an xmlXPathObjectPtr object.
766 */
767void
768xmlXPathFreeObject(xmlXPathObjectPtr obj) {
769 if (obj == NULL) return;
770 if (obj->nodesetval != NULL)
771 xmlXPathFreeNodeSet(obj->nodesetval);
772 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000773 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000774#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000775 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000776#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000777 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000778}
779
780/************************************************************************
781 * *
782 * Routines to handle XPath contexts *
783 * *
784 ************************************************************************/
785
786/**
787 * xmlXPathNewContext:
788 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000789 *
790 * Create a new xmlXPathContext
791 *
792 * Returns the xmlXPathContext just allocated.
793 */
794xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000795xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000796 xmlXPathContextPtr ret;
797
Daniel Veillard6454aec1999-09-02 22:04:43 +0000798 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000799 if (ret == NULL) {
800 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
801 return(NULL);
802 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000803 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000804 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000805 /***********
806 ret->node = (xmlNodePtr) doc;
807 ret->nodelist = xmlXPathNodeSetCreate(ret->node);
808 ***********/
809 ret->node = NULL;
810 ret->nodelist = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000811
812 ret->nb_variables = 0;
813 ret->max_variables = 0;
814 ret->variables = NULL;
815
816 ret->nb_types = 0;
817 ret->max_types = 0;
818 ret->types = NULL;
819
820 ret->nb_funcs = 0;
821 ret->max_funcs = 0;
822 ret->funcs = NULL;
823
824 ret->nb_axis = 0;
825 ret->max_axis = 0;
826 ret->axis = NULL;
827
Daniel Veillardb96e6431999-08-29 21:02:19 +0000828 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000829 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000830 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000831 return(ret);
832}
833
834/**
835 * xmlXPathFreeContext:
836 * @ctxt: the context to free
837 *
838 * Free up an xmlXPathContext
839 */
840void
841xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000842 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000843 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000844
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000845 /***********
846 if (ctxt->nodelist != NULL)
847 xmlXPathFreeNodeSet(ctxt->nodelist);
848 ***********/
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000849#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000850 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000851#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000852 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000853}
854
855/************************************************************************
856 * *
857 * Routines to handle XPath parser contexts *
858 * *
859 ************************************************************************/
860
861#define CHECK_CTXT \
862 if (ctxt == NULL) { \
863 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
864 __FILE__, __LINE__); \
865 } \
866
867
868#define CHECK_CONTEXT \
869 if (ctxt == NULL) { \
870 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
871 __FILE__, __LINE__); \
872 } \
873 if (ctxt->doc == NULL) { \
874 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
875 __FILE__, __LINE__); \
876 } \
Daniel Veillardcf461992000-03-14 18:30:20 +0000877 if (ctxt->doc->children == NULL) { \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000878 fprintf(xmlXPathDebug, \
879 "%s:%d Internal error: document without root\n", \
880 __FILE__, __LINE__); \
881 } \
882
883
884/**
885 * xmlXPathNewParserContext:
886 * @str: the XPath expression
887 * @ctxt: the XPath context
888 *
889 * Create a new xmlXPathParserContext
890 *
891 * Returns the xmlXPathParserContext just allocated.
892 */
893xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000894xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000895 xmlXPathParserContextPtr ret;
896
Daniel Veillard6454aec1999-09-02 22:04:43 +0000897 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000898 if (ret == NULL) {
899 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
900 return(NULL);
901 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000902 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000903 ret->cur = ret->base = str;
904 ret->context = ctxt;
905
906 /* Allocate the value stack */
907 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000908 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000909 ret->valueNr = 0;
910 ret->valueMax = 10;
911 ret->value = NULL;
912 return(ret);
913}
914
915/**
916 * xmlXPathFreeParserContext:
917 * @ctxt: the context to free
918 *
919 * Free up an xmlXPathParserContext
920 */
921void
922xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
923 if (ctxt->valueTab != NULL) {
924#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000925 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000926#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000927 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000928 }
929#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000930 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000931#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000932 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000933}
934
935/************************************************************************
936 * *
937 * The implicit core function library *
938 * *
939 ************************************************************************/
940
941/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000942 * Auto-pop and cast to a number
943 */
944void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
945
946#define CHECK_ARITY(x) \
947 if (nargs != (x)) { \
948 ERROR(XPATH_INVALID_ARITY); \
949 } \
950
951
952#define POP_FLOAT \
953 arg = valuePop(ctxt); \
954 if (arg == NULL) { \
955 ERROR(XPATH_INVALID_OPERAND); \
956 } \
957 if (arg->type != XPATH_NUMBER) { \
958 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000959 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000960 arg = valuePop(ctxt); \
961 }
962
963/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000964 * xmlXPathEqualNodeSetString
965 * @arg: the nodeset object argument
966 * @str: the string to compare to.
967 *
968 * Implement the equal operation on XPath objects content: @arg1 == @arg2
969 * If one object to be compared is a node-set and the other is a string,
970 * then the comparison will be true if and only if there is a node in
971 * the node-set such that the result of performing the comparison on the
972 * string-value of the node and the other string is true.
973 *
974 * Returns 0 or 1 depending on the results of the test.
975 */
976int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000977xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000978 int i;
979 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000980 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000981
982 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
983 return(0);
984 ns = arg->nodesetval;
985 for (i = 0;i < ns->nodeNr;i++) {
986 str2 = xmlNodeGetContent(ns->nodeTab[i]);
987 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000988 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000989 return(1);
990 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000991 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000992 }
993 return(0);
994}
995
996/**
997 * xmlXPathEqualNodeSetFloat
998 * @arg: the nodeset object argument
999 * @f: the float to compare to
1000 *
1001 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1002 * If one object to be compared is a node-set and the other is a number,
1003 * then the comparison will be true if and only if there is a node in
1004 * the node-set such that the result of performing the comparison on the
1005 * number to be compared and on the result of converting the string-value
1006 * of that node to a number using the number function is true.
1007 *
1008 * Returns 0 or 1 depending on the results of the test.
1009 */
1010int
1011xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001012 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001013
1014 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1015 return(0);
1016
1017 if (isnan(f))
1018 sprintf(buf, "NaN");
1019 else if (isinf(f) > 0)
1020 sprintf(buf, "+Infinity");
1021 else if (isinf(f) < 0)
1022 sprintf(buf, "-Infinity");
1023 else
1024 sprintf(buf, "%0g", f);
1025
Daniel Veillardb96e6431999-08-29 21:02:19 +00001026 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001027}
1028
1029
1030/**
1031 * xmlXPathEqualNodeSets
1032 * @arg1: first nodeset object argument
1033 * @arg2: second nodeset object argument
1034 *
1035 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1036 * If both objects to be compared are node-sets, then the comparison
1037 * will be true if and only if there is a node in the first node-set and
1038 * a node in the second node-set such that the result of performing the
1039 * comparison on the string-values of the two nodes is true.
1040 *
1041 * (needless to say, this is a costly operation)
1042 *
1043 * Returns 0 or 1 depending on the results of the test.
1044 */
1045int
1046xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1047 int i;
1048 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001049 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001050
1051 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1052 return(0);
1053 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1054 return(0);
1055
1056 ns = arg1->nodesetval;
1057 for (i = 0;i < ns->nodeNr;i++) {
1058 str = xmlNodeGetContent(ns->nodeTab[i]);
1059 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001060 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001061 return(1);
1062 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001063 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001064 }
1065 return(0);
1066}
1067
1068/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001069 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001070 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001071 *
1072 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1073 *
1074 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001075 */
1076int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001077xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1078 xmlXPathObjectPtr arg1, arg2;
1079 int ret = 0;
1080
1081 arg1 = valuePop(ctxt);
1082 if (arg1 == NULL)
1083 ERROR0(XPATH_INVALID_OPERAND);
1084
1085 arg2 = valuePop(ctxt);
1086 if (arg2 == NULL) {
1087 xmlXPathFreeObject(arg1);
1088 ERROR0(XPATH_INVALID_OPERAND);
1089 }
1090
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001091 if (arg1 == arg2) {
1092#ifdef DEBUG_EXPR
1093 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1094#endif
1095 return(1);
1096 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001097
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001098 switch (arg1->type) {
1099 case XPATH_UNDEFINED:
1100#ifdef DEBUG_EXPR
1101 fprintf(xmlXPathDebug, "Equal: undefined\n");
1102#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001103 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001104 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001105 switch (arg2->type) {
1106 case XPATH_UNDEFINED:
1107#ifdef DEBUG_EXPR
1108 fprintf(xmlXPathDebug, "Equal: undefined\n");
1109#endif
1110 break;
1111 case XPATH_NODESET:
1112 ret = xmlXPathEqualNodeSets(arg1, arg2);
1113 break;
1114 case XPATH_BOOLEAN:
1115 if ((arg1->nodesetval == NULL) ||
1116 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1117 else
1118 ret = 1;
1119 ret = (ret == arg2->boolval);
1120 break;
1121 case XPATH_NUMBER:
1122 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1123 break;
1124 case XPATH_STRING:
1125 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1126 break;
1127 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001128 break;
1129 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001130 switch (arg2->type) {
1131 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001132#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001133 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001134#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001135 break;
1136 case XPATH_NODESET:
1137 if ((arg2->nodesetval == NULL) ||
1138 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1139 else
1140 ret = 1;
1141 break;
1142 case XPATH_BOOLEAN:
1143#ifdef DEBUG_EXPR
1144 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1145 arg1->boolval, arg2->boolval);
1146#endif
1147 ret = (arg1->boolval == arg2->boolval);
1148 break;
1149 case XPATH_NUMBER:
1150 if (arg2->floatval) ret = 1;
1151 else ret = 0;
1152 ret = (arg1->boolval == ret);
1153 break;
1154 case XPATH_STRING:
1155 if ((arg2->stringval == NULL) ||
1156 (arg2->stringval[0] == 0)) ret = 0;
1157 else
1158 ret = 1;
1159 ret = (arg1->boolval == ret);
1160 break;
1161 }
1162 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001163 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001164 switch (arg2->type) {
1165 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001166#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001167 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001168#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001169 break;
1170 case XPATH_NODESET:
1171 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1172 break;
1173 case XPATH_BOOLEAN:
1174 if (arg1->floatval) ret = 1;
1175 else ret = 0;
1176 ret = (arg2->boolval == ret);
1177 break;
1178 case XPATH_STRING:
1179 valuePush(ctxt, arg2);
1180 xmlXPathNumberFunction(ctxt, 1);
1181 arg2 = valuePop(ctxt);
1182 /* no break on purpose */
1183 case XPATH_NUMBER:
1184 ret = (arg1->floatval == arg2->floatval);
1185 break;
1186 }
1187 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001188 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001189 switch (arg2->type) {
1190 case XPATH_UNDEFINED:
1191#ifdef DEBUG_EXPR
1192 fprintf(xmlXPathDebug, "Equal: undefined\n");
1193#endif
1194 break;
1195 case XPATH_NODESET:
1196 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1197 break;
1198 case XPATH_BOOLEAN:
1199 if ((arg1->stringval == NULL) ||
1200 (arg1->stringval[0] == 0)) ret = 0;
1201 else
1202 ret = 1;
1203 ret = (arg2->boolval == ret);
1204 break;
1205 case XPATH_STRING:
1206 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1207 break;
1208 case XPATH_NUMBER:
1209 valuePush(ctxt, arg1);
1210 xmlXPathNumberFunction(ctxt, 1);
1211 arg1 = valuePop(ctxt);
1212 ret = (arg1->floatval == arg2->floatval);
1213 break;
1214 }
1215 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001216 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001217 xmlXPathFreeObject(arg1);
1218 xmlXPathFreeObject(arg2);
1219 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001220}
1221
1222/**
1223 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001224 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001225 * @inf: less than (1) or greater than (2)
1226 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001227 *
1228 * Implement the compare operation on XPath objects:
1229 * @arg1 < @arg2 (1, 1, ...
1230 * @arg1 <= @arg2 (1, 0, ...
1231 * @arg1 > @arg2 (0, 1, ...
1232 * @arg1 >= @arg2 (0, 0, ...
1233 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001234 * When neither object to be compared is a node-set and the operator is
1235 * <=, <, >=, >, then the objects are compared by converted both objects
1236 * to numbers and comparing the numbers according to IEEE 754. The <
1237 * comparison will be true if and only if the first number is less than the
1238 * second number. The <= comparison will be true if and only if the first
1239 * number is less than or equal to the second number. The > comparison
1240 * will be true if and only if the first number is greater than the second
1241 * number. The >= comparison will be true if and only if the first number
1242 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001243 */
1244int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001245xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1246 int ret = 0;
1247 xmlXPathObjectPtr arg1, arg2;
1248
1249 arg2 = valuePop(ctxt);
1250 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1251 if (arg2 != NULL)
1252 xmlXPathFreeObject(arg2);
1253 ERROR0(XPATH_INVALID_OPERAND);
1254 }
1255
1256 arg1 = valuePop(ctxt);
1257 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1258 if (arg1 != NULL)
1259 xmlXPathFreeObject(arg1);
1260 xmlXPathFreeObject(arg2);
1261 ERROR0(XPATH_INVALID_OPERAND);
1262 }
1263
1264 if (arg1->type != XPATH_NUMBER) {
1265 valuePush(ctxt, arg1);
1266 xmlXPathNumberFunction(ctxt, 1);
1267 arg1 = valuePop(ctxt);
1268 }
1269 if (arg1->type != XPATH_NUMBER) {
1270 xmlXPathFreeObject(arg1);
1271 xmlXPathFreeObject(arg2);
1272 ERROR0(XPATH_INVALID_OPERAND);
1273 }
1274 if (arg2->type != XPATH_NUMBER) {
1275 valuePush(ctxt, arg2);
1276 xmlXPathNumberFunction(ctxt, 1);
1277 arg2 = valuePop(ctxt);
1278 }
1279 if (arg2->type != XPATH_NUMBER) {
1280 xmlXPathFreeObject(arg1);
1281 xmlXPathFreeObject(arg2);
1282 ERROR0(XPATH_INVALID_OPERAND);
1283 }
1284 /*
1285 * Add tests for infinity and nan
1286 * => feedback on 3.4 for Inf and NaN
1287 */
1288 if (inf && strict)
1289 ret = (arg1->floatval < arg2->floatval);
1290 else if (inf && !strict)
1291 ret = (arg1->floatval <= arg2->floatval);
1292 else if (!inf && strict)
1293 ret = (arg1->floatval > arg2->floatval);
1294 else if (!inf && !strict)
1295 ret = (arg1->floatval >= arg2->floatval);
1296 xmlXPathFreeObject(arg1);
1297 xmlXPathFreeObject(arg2);
1298 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001299}
1300
1301/**
1302 * xmlXPathValueFlipSign:
1303 * @ctxt: the XPath Parser context
1304 *
1305 * Implement the unary - operation on an XPath object
1306 * The numeric operators convert their operands to numbers as if
1307 * by calling the number function.
1308 */
1309void
1310xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1311 xmlXPathObjectPtr arg;
1312
1313 POP_FLOAT
1314 arg->floatval = -arg->floatval;
1315 valuePush(ctxt, arg);
1316}
1317
1318/**
1319 * xmlXPathAddValues:
1320 * @ctxt: the XPath Parser context
1321 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001322 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001323 * The numeric operators convert their operands to numbers as if
1324 * by calling the number function.
1325 */
1326void
1327xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1328 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001329 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001330
1331 POP_FLOAT
1332 val = arg->floatval;
1333 xmlXPathFreeObject(arg);
1334
1335 POP_FLOAT
1336 arg->floatval += val;
1337 valuePush(ctxt, arg);
1338}
1339
1340/**
1341 * xmlXPathSubValues:
1342 * @ctxt: the XPath Parser context
1343 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001344 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001345 * The numeric operators convert their operands to numbers as if
1346 * by calling the number function.
1347 */
1348void
1349xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1350 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001351 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001352
1353 POP_FLOAT
1354 val = arg->floatval;
1355 xmlXPathFreeObject(arg);
1356
1357 POP_FLOAT
1358 arg->floatval -= val;
1359 valuePush(ctxt, arg);
1360}
1361
1362/**
1363 * xmlXPathMultValues:
1364 * @ctxt: the XPath Parser context
1365 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001366 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001367 * The numeric operators convert their operands to numbers as if
1368 * by calling the number function.
1369 */
1370void
1371xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1372 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001373 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001374
1375 POP_FLOAT
1376 val = arg->floatval;
1377 xmlXPathFreeObject(arg);
1378
1379 POP_FLOAT
1380 arg->floatval *= val;
1381 valuePush(ctxt, arg);
1382}
1383
1384/**
1385 * xmlXPathDivValues:
1386 * @ctxt: the XPath Parser context
1387 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001388 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001389 * The numeric operators convert their operands to numbers as if
1390 * by calling the number function.
1391 */
1392void
1393xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1394 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001395 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001396
1397 POP_FLOAT
1398 val = arg->floatval;
1399 xmlXPathFreeObject(arg);
1400
1401 POP_FLOAT
1402 arg->floatval /= val;
1403 valuePush(ctxt, arg);
1404}
1405
1406/**
1407 * xmlXPathModValues:
1408 * @ctxt: the XPath Parser context
1409 *
1410 * Implement the div operation on XPath objects: @arg1 / @arg2
1411 * The numeric operators convert their operands to numbers as if
1412 * by calling the number function.
1413 */
1414void
1415xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1416 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001417 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001418
1419 POP_FLOAT
1420 val = arg->floatval;
1421 xmlXPathFreeObject(arg);
1422
1423 POP_FLOAT
1424 arg->floatval /= val;
1425 valuePush(ctxt, arg);
1426}
1427
1428/************************************************************************
1429 * *
1430 * The traversal functions *
1431 * *
1432 ************************************************************************/
1433
1434#define AXIS_ANCESTOR 1
1435#define AXIS_ANCESTOR_OR_SELF 2
1436#define AXIS_ATTRIBUTE 3
1437#define AXIS_CHILD 4
1438#define AXIS_DESCENDANT 5
1439#define AXIS_DESCENDANT_OR_SELF 6
1440#define AXIS_FOLLOWING 7
1441#define AXIS_FOLLOWING_SIBLING 8
1442#define AXIS_NAMESPACE 9
1443#define AXIS_PARENT 10
1444#define AXIS_PRECEDING 11
1445#define AXIS_PRECEDING_SIBLING 12
1446#define AXIS_SELF 13
1447
1448/*
1449 * A traversal function enumerates nodes along an axis.
1450 * Initially it must be called with NULL, and it indicates
1451 * termination on the axis by returning NULL.
1452 */
1453typedef xmlNodePtr (*xmlXPathTraversalFunction)
1454 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1455
1456/**
1457 * mlXPathNextSelf:
1458 * @ctxt: the XPath Parser context
1459 * @cur: the current node in the traversal
1460 *
1461 * Traversal function for the "self" direction
1462 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001463 *
1464 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001465 */
1466xmlNodePtr
1467xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1468 if (cur == NULL)
1469 return(ctxt->context->node);
1470 return(NULL);
1471}
1472
1473/**
1474 * mlXPathNextChild:
1475 * @ctxt: the XPath Parser context
1476 * @cur: the current node in the traversal
1477 *
1478 * Traversal function for the "child" direction
1479 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001480 *
1481 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001482 */
1483xmlNodePtr
1484xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001485 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001486 if (ctxt->context->node == NULL) return(NULL);
1487 switch (ctxt->context->node->type) {
1488 case XML_ELEMENT_NODE:
1489 case XML_TEXT_NODE:
1490 case XML_CDATA_SECTION_NODE:
1491 case XML_ENTITY_REF_NODE:
1492 case XML_ENTITY_NODE:
1493 case XML_PI_NODE:
1494 case XML_COMMENT_NODE:
1495 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001496 case XML_DTD_NODE:
1497 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001498 case XML_DOCUMENT_NODE:
1499 case XML_DOCUMENT_TYPE_NODE:
1500 case XML_DOCUMENT_FRAG_NODE:
1501 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001502 return(((xmlDocPtr) ctxt->context->node)->children);
1503 case XML_ELEMENT_DECL:
1504 case XML_ATTRIBUTE_DECL:
1505 case XML_ENTITY_DECL:
1506 case XML_ATTRIBUTE_NODE:
1507 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001508 }
1509 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001510 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001511 if ((cur->type == XML_DOCUMENT_NODE) ||
1512 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001513 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001514 return(cur->next);
1515}
1516
1517/**
1518 * mlXPathNextDescendant:
1519 * @ctxt: the XPath Parser context
1520 * @cur: the current node in the traversal
1521 *
1522 * Traversal function for the "descendant" direction
1523 * the descendant axis contains the descendants of the context node in document
1524 * order; a descendant is a child or a child of a child and so on.
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
1529xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001530 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001531 if (ctxt->context->node == NULL)
1532 return(NULL);
1533 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1534 return(NULL);
1535
Daniel Veillardb05deb71999-08-10 19:04:08 +00001536 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00001537 return(ctxt->context->doc->children);
1538 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001539 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001540
Daniel Veillardcf461992000-03-14 18:30:20 +00001541 if (cur->children != NULL) return(cur->children);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001542 if (cur->next != NULL) return(cur->next);
1543
1544 do {
1545 cur = cur->parent;
1546 if (cur == NULL) return(NULL);
1547 if (cur == ctxt->context->node) return(NULL);
1548 if (cur->next != NULL) {
1549 cur = cur->next;
1550 return(cur);
1551 }
1552 } while (cur != NULL);
1553 return(cur);
1554}
1555
1556/**
1557 * mlXPathNextDescendantOrSelf:
1558 * @ctxt: the XPath Parser context
1559 * @cur: the current node in the traversal
1560 *
1561 * Traversal function for the "descendant-or-self" direction
1562 * the descendant-or-self axis contains the context node and the descendants
1563 * of the context node in document order; thus the context node is the first
1564 * node on the axis, and the first child of the context node is the second node
1565 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001566 *
1567 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001568 */
1569xmlNodePtr
1570xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001571 if (cur == NULL) {
1572 if (ctxt->context->node == NULL)
1573 return(NULL);
1574 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1575 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001576 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001577 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001578
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001579 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001580}
1581
1582/**
1583 * xmlXPathNextParent:
1584 * @ctxt: the XPath Parser context
1585 * @cur: the current node in the traversal
1586 *
1587 * Traversal function for the "parent" direction
1588 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001589 *
1590 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001591 */
1592xmlNodePtr
1593xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1594 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001595 * the parent of an attribute or namespace node is the element
1596 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001597 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001598 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001599 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001600 if (ctxt->context->node == NULL) return(NULL);
1601 switch (ctxt->context->node->type) {
1602 case XML_ELEMENT_NODE:
1603 case XML_TEXT_NODE:
1604 case XML_CDATA_SECTION_NODE:
1605 case XML_ENTITY_REF_NODE:
1606 case XML_ENTITY_NODE:
1607 case XML_PI_NODE:
1608 case XML_COMMENT_NODE:
1609 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001610 case XML_DTD_NODE:
1611 case XML_ELEMENT_DECL:
1612 case XML_ATTRIBUTE_DECL:
1613 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001614 if (ctxt->context->node->parent == NULL)
1615 return((xmlNodePtr) ctxt->context->doc);
1616 return(ctxt->context->node->parent);
1617 case XML_ATTRIBUTE_NODE: {
1618 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1619
Daniel Veillardcf461992000-03-14 18:30:20 +00001620 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001621 }
1622 case XML_DOCUMENT_NODE:
1623 case XML_DOCUMENT_TYPE_NODE:
1624 case XML_DOCUMENT_FRAG_NODE:
1625 case XML_HTML_DOCUMENT_NODE:
1626 return(NULL);
1627 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001628 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001629 return(NULL);
1630}
1631
1632/**
1633 * xmlXPathNextAncestor:
1634 * @ctxt: the XPath Parser context
1635 * @cur: the current node in the traversal
1636 *
1637 * Traversal function for the "ancestor" direction
1638 * the ancestor axis contains the ancestors of the context node; the ancestors
1639 * of the context node consist of the parent of context node and the parent's
1640 * parent and so on; the nodes are ordered in reverse document order; thus the
1641 * parent is the first node on the axis, and the parent's parent is the second
1642 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001643 *
1644 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001645 */
1646xmlNodePtr
1647xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1648 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001649 * the parent of an attribute or namespace node is the element
1650 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001651 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001652 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001653 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001654 if (ctxt->context->node == NULL) return(NULL);
1655 switch (ctxt->context->node->type) {
1656 case XML_ELEMENT_NODE:
1657 case XML_TEXT_NODE:
1658 case XML_CDATA_SECTION_NODE:
1659 case XML_ENTITY_REF_NODE:
1660 case XML_ENTITY_NODE:
1661 case XML_PI_NODE:
1662 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001663 case XML_DTD_NODE:
1664 case XML_ELEMENT_DECL:
1665 case XML_ATTRIBUTE_DECL:
1666 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001667 case XML_NOTATION_NODE:
1668 if (ctxt->context->node->parent == NULL)
1669 return((xmlNodePtr) ctxt->context->doc);
1670 return(ctxt->context->node->parent);
1671 case XML_ATTRIBUTE_NODE: {
1672 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
1673
Daniel Veillardcf461992000-03-14 18:30:20 +00001674 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001675 }
1676 case XML_DOCUMENT_NODE:
1677 case XML_DOCUMENT_TYPE_NODE:
1678 case XML_DOCUMENT_FRAG_NODE:
1679 case XML_HTML_DOCUMENT_NODE:
1680 return(NULL);
1681 }
1682 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001683 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001684 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00001685 return((xmlNodePtr) ctxt->context->doc);
1686 if (cur == (xmlNodePtr) ctxt->context->doc)
1687 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001688 switch (cur->type) {
1689 case XML_ELEMENT_NODE:
1690 case XML_TEXT_NODE:
1691 case XML_CDATA_SECTION_NODE:
1692 case XML_ENTITY_REF_NODE:
1693 case XML_ENTITY_NODE:
1694 case XML_PI_NODE:
1695 case XML_COMMENT_NODE:
1696 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001697 case XML_DTD_NODE:
1698 case XML_ELEMENT_DECL:
1699 case XML_ATTRIBUTE_DECL:
1700 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001701 return(cur->parent);
1702 case XML_ATTRIBUTE_NODE: {
1703 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1704
Daniel Veillardcf461992000-03-14 18:30:20 +00001705 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001706 }
1707 case XML_DOCUMENT_NODE:
1708 case XML_DOCUMENT_TYPE_NODE:
1709 case XML_DOCUMENT_FRAG_NODE:
1710 case XML_HTML_DOCUMENT_NODE:
1711 return(NULL);
1712 }
1713 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001714}
1715
1716/**
1717 * xmlXPathNextAncestorOrSelf:
1718 * @ctxt: the XPath Parser context
1719 * @cur: the current node in the traversal
1720 *
1721 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001722 * he ancestor-or-self axis contains the context node and ancestors of
1723 * the context node in reverse document order; thus the context node is
1724 * the first node on the axis, and the context node's parent the second;
1725 * parent here is defined the same as with the parent axis.
1726 *
1727 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001728 */
1729xmlNodePtr
1730xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001731 if (cur == NULL)
1732 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001733 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001734}
1735
1736/**
1737 * xmlXPathNextFollowingSibling:
1738 * @ctxt: the XPath Parser context
1739 * @cur: the current node in the traversal
1740 *
1741 * Traversal function for the "following-sibling" direction
1742 * The following-sibling axis contains the following siblings of the context
1743 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001744 *
1745 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001746 */
1747xmlNodePtr
1748xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001749 if (cur == (xmlNodePtr) ctxt->context->doc)
1750 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001751 if (cur == NULL)
1752 return(ctxt->context->node->next);
1753 return(cur->next);
1754}
1755
1756/**
1757 * xmlXPathNextPrecedingSibling:
1758 * @ctxt: the XPath Parser context
1759 * @cur: the current node in the traversal
1760 *
1761 * Traversal function for the "preceding-sibling" direction
1762 * The preceding-sibling axis contains the preceding siblings of the context
1763 * node in reverse document order; the first preceding sibling is first on the
1764 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001765 *
1766 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001767 */
1768xmlNodePtr
1769xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001770 if (cur == (xmlNodePtr) ctxt->context->doc)
1771 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001772 if (cur == NULL)
1773 return(ctxt->context->node->prev);
1774 return(cur->prev);
1775}
1776
1777/**
1778 * xmlXPathNextFollowing:
1779 * @ctxt: the XPath Parser context
1780 * @cur: the current node in the traversal
1781 *
1782 * Traversal function for the "following" direction
1783 * The following axis contains all nodes in the same document as the context
1784 * node that are after the context node in document order, excluding any
1785 * descendants and excluding attribute nodes and namespace nodes; the nodes
1786 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001787 *
1788 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001789 */
1790xmlNodePtr
1791xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001792 if (cur == (xmlNodePtr) ctxt->context->doc)
1793 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001794 if (cur == NULL)
1795 return(ctxt->context->node->next);; /* !!!!!!!!! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001796 if (cur->children != NULL) return(cur->children);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001797 if (cur->next != NULL) return(cur->next);
1798
1799 do {
1800 cur = cur->parent;
1801 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00001802 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001803 if (cur->next != NULL) {
1804 cur = cur->next;
1805 return(cur);
1806 }
1807 } while (cur != NULL);
1808 return(cur);
1809}
1810
1811/**
1812 * xmlXPathNextPreceding:
1813 * @ctxt: the XPath Parser context
1814 * @cur: the current node in the traversal
1815 *
1816 * Traversal function for the "preceding" direction
1817 * the preceding axis contains all nodes in the same document as the context
1818 * node that are before the context node in document order, excluding any
1819 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1820 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001821 *
1822 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001823 */
1824xmlNodePtr
1825xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001826 if (cur == (xmlNodePtr) ctxt->context->doc)
1827 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001828 if (cur == NULL)
1829 return(ctxt->context->node->prev); /* !!!!!!!!! */
1830 if (cur->last != NULL) return(cur->last);
1831 if (cur->prev != NULL) return(cur->prev);
1832
1833 do {
1834 cur = cur->parent;
1835 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00001836 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001837 if (cur->prev != NULL) {
1838 cur = cur->prev;
1839 return(cur);
1840 }
1841 } while (cur != NULL);
1842 return(cur);
1843}
1844
1845/**
1846 * xmlXPathNextNamespace:
1847 * @ctxt: the XPath Parser context
1848 * @cur: the current attribute in the traversal
1849 *
1850 * Traversal function for the "namespace" direction
1851 * the namespace axis contains the namespace nodes of the context node;
1852 * the order of nodes on this axis is implementation-defined; the axis will
1853 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001854 *
1855 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001856 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001857xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001858xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001859 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1860 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001861 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001862 ctxt->context->namespaces =
1863 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1864 if (ctxt->context->namespaces == NULL) return(NULL);
1865 ctxt->context->nsNr = 0;
1866 }
1867 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001868}
1869
1870/**
1871 * xmlXPathNextAttribute:
1872 * @ctxt: the XPath Parser context
1873 * @cur: the current attribute in the traversal
1874 *
1875 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001876 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001877 *
1878 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001879 */
1880xmlAttrPtr
1881xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001882 if (cur == NULL) {
1883 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1884 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001885 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001886 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001887 return(cur->next);
1888}
1889
1890/************************************************************************
1891 * *
1892 * NodeTest Functions *
1893 * *
1894 ************************************************************************/
1895
1896#define NODE_TEST_NONE 0
1897#define NODE_TEST_TYPE 1
1898#define NODE_TEST_PI 2
1899#define NODE_TEST_ALL 3
1900#define NODE_TEST_NS 4
1901#define NODE_TEST_NAME 5
1902
1903#define NODE_TYPE_COMMENT 50
1904#define NODE_TYPE_TEXT 51
1905#define NODE_TYPE_PI 52
1906#define NODE_TYPE_NODE 53
1907
1908#define IS_FUNCTION 200
1909
1910/**
1911 * xmlXPathNodeCollectAndTest:
1912 * @ctxt: the XPath Parser context
1913 * @cur: the current node to test
1914 *
1915 * This is the function implementing a step: based on the current list
1916 * of nodes, it builds up a new list, looking at all nodes under that
1917 * axis and selecting them.
1918 *
1919 * Returns the new NodeSet resulting from the search.
1920 */
1921xmlNodeSetPtr
1922xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001923 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001924#ifdef DEBUG_STEP
1925 int n = 0, t = 0;
1926#endif
1927 int i;
1928 xmlNodeSetPtr ret;
1929 xmlXPathTraversalFunction next = NULL;
1930 xmlNodePtr cur = NULL;
1931
1932 if (ctxt->context->nodelist == NULL) {
1933 if (ctxt->context->node == NULL) {
1934 fprintf(xmlXPathDebug,
1935 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1936 __FILE__, __LINE__);
1937 return(NULL);
1938 }
1939 STRANGE
1940 return(NULL);
1941 }
1942#ifdef DEBUG_STEP
1943 fprintf(xmlXPathDebug, "new step : ");
1944#endif
1945 switch (axis) {
1946 case AXIS_ANCESTOR:
1947#ifdef DEBUG_STEP
1948 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1949#endif
1950 next = xmlXPathNextAncestor; break;
1951 case AXIS_ANCESTOR_OR_SELF:
1952#ifdef DEBUG_STEP
1953 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1954#endif
1955 next = xmlXPathNextAncestorOrSelf; break;
1956 case AXIS_ATTRIBUTE:
1957#ifdef DEBUG_STEP
1958 fprintf(xmlXPathDebug, "axis 'attributes' ");
1959#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001960 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001961 break;
1962 case AXIS_CHILD:
1963#ifdef DEBUG_STEP
1964 fprintf(xmlXPathDebug, "axis 'child' ");
1965#endif
1966 next = xmlXPathNextChild; break;
1967 case AXIS_DESCENDANT:
1968#ifdef DEBUG_STEP
1969 fprintf(xmlXPathDebug, "axis 'descendant' ");
1970#endif
1971 next = xmlXPathNextDescendant; break;
1972 case AXIS_DESCENDANT_OR_SELF:
1973#ifdef DEBUG_STEP
1974 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1975#endif
1976 next = xmlXPathNextDescendantOrSelf; break;
1977 case AXIS_FOLLOWING:
1978#ifdef DEBUG_STEP
1979 fprintf(xmlXPathDebug, "axis 'following' ");
1980#endif
1981 next = xmlXPathNextFollowing; break;
1982 case AXIS_FOLLOWING_SIBLING:
1983#ifdef DEBUG_STEP
1984 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1985#endif
1986 next = xmlXPathNextFollowingSibling; break;
1987 case AXIS_NAMESPACE:
1988#ifdef DEBUG_STEP
1989 fprintf(xmlXPathDebug, "axis 'namespace' ");
1990#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001991 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001992 break;
1993 case AXIS_PARENT:
1994#ifdef DEBUG_STEP
1995 fprintf(xmlXPathDebug, "axis 'parent' ");
1996#endif
1997 next = xmlXPathNextParent; break;
1998 case AXIS_PRECEDING:
1999#ifdef DEBUG_STEP
2000 fprintf(xmlXPathDebug, "axis 'preceding' ");
2001#endif
2002 next = xmlXPathNextPreceding; break;
2003 case AXIS_PRECEDING_SIBLING:
2004#ifdef DEBUG_STEP
2005 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
2006#endif
2007 next = xmlXPathNextPrecedingSibling; break;
2008 case AXIS_SELF:
2009#ifdef DEBUG_STEP
2010 fprintf(xmlXPathDebug, "axis 'self' ");
2011#endif
2012 next = xmlXPathNextSelf; break;
2013 }
2014 if (next == NULL) return(NULL);
2015 ret = xmlXPathNodeSetCreate(NULL);
2016#ifdef DEBUG_STEP
2017 fprintf(xmlXPathDebug, " context contains %d nodes\n",
2018 ctxt->context->nodelist->nodeNr);
2019 switch (test) {
2020 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002021 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002022 break;
2023 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002024 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002025 break;
2026 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002027 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002028 break;
2029 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002030 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002031 break;
2032 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002033 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002034 prefix);
2035 break;
2036 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002037 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002038 if (prefix != NULL)
2039 fprintf(xmlXPathDebug, " with namespace %s\n",
2040 prefix);
2041 break;
2042 }
2043 fprintf(xmlXPathDebug, "Testing : ");
2044#endif
2045 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
2046 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
2047
2048 cur = NULL;
2049 do {
2050 cur = next(ctxt, cur);
2051 if (cur == NULL) break;
2052#ifdef DEBUG_STEP
2053 t++;
2054 fprintf(xmlXPathDebug, " %s", cur->name);
2055#endif
2056 switch (test) {
2057 case NODE_TEST_NONE:
2058 STRANGE
2059 return(NULL);
2060 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002061 if ((cur->type == type) ||
2062 ((type == XML_ELEMENT_NODE) &&
2063 ((cur->type == XML_DOCUMENT_NODE) ||
2064 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002065#ifdef DEBUG_STEP
2066 n++;
2067#endif
2068 xmlXPathNodeSetAdd(ret, cur);
2069 }
2070 break;
2071 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002072 if (cur->type == XML_PI_NODE) {
2073 if ((name != NULL) &&
2074 (xmlStrcmp(name, cur->name)))
2075 break;
2076#ifdef DEBUG_STEP
2077 n++;
2078#endif
2079 xmlXPathNodeSetAdd(ret, cur);
2080 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002081 break;
2082 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002083 if ((cur->type == XML_ELEMENT_NODE) ||
2084 (cur->type == XML_ATTRIBUTE_NODE)) {
2085 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002086#ifdef DEBUG_STEP
2087 n++;
2088#endif
2089 xmlXPathNodeSetAdd(ret, cur);
2090 }
2091 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002092 case NODE_TEST_NS: {
2093 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002094 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002095 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002096 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002097 switch (cur->type) {
2098 case XML_ELEMENT_NODE:
2099 if (!xmlStrcmp(name, cur->name) &&
2100 (((prefix == NULL) ||
2101 ((cur->ns != NULL) &&
2102 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002103#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002104 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002105#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002106 xmlXPathNodeSetAdd(ret, cur);
2107 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002108 break;
2109 case XML_ATTRIBUTE_NODE: {
2110 xmlAttrPtr attr = (xmlAttrPtr) cur;
2111 if (!xmlStrcmp(name, attr->name)) {
2112#ifdef DEBUG_STEP
2113 n++;
2114#endif
2115 xmlXPathNodeSetAdd(ret, cur);
2116 }
2117 break;
2118 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002119 default:
2120 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002121 }
2122 break;
2123
2124 }
2125 } while (cur != NULL);
2126 }
2127#ifdef DEBUG_STEP
2128 fprintf(xmlXPathDebug,
2129 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2130#endif
2131 return(ret);
2132}
2133
2134
2135/************************************************************************
2136 * *
2137 * Implicit tree core function library *
2138 * *
2139 ************************************************************************/
2140
2141/**
2142 * xmlXPathRoot:
2143 * @ctxt: the XPath Parser context
2144 *
2145 * Initialize the context to the root of the document
2146 */
2147void
2148xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2149 if (ctxt->context->nodelist != NULL)
2150 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002151 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2152 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002153}
2154
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002155/************************************************************************
2156 * *
2157 * The explicit core function library *
2158 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2159 * *
2160 ************************************************************************/
2161
2162
2163/**
2164 * xmlXPathLastFunction:
2165 * @ctxt: the XPath Parser context
2166 *
2167 * Implement the last() XPath function
2168 * The last function returns the number of nodes in the context node list.
2169 */
2170void
2171xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2172 CHECK_ARITY(0);
2173 if ((ctxt->context->nodelist == NULL) ||
2174 (ctxt->context->node == NULL) ||
2175 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002176 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002177 } else {
2178 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002179 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002180 }
2181}
2182
2183/**
2184 * xmlXPathPositionFunction:
2185 * @ctxt: the XPath Parser context
2186 *
2187 * Implement the position() XPath function
2188 * The position function returns the position of the context node in the
2189 * context node list. The first position is 1, and so the last positionr
2190 * will be equal to last().
2191 */
2192void
2193xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2194 int i;
2195
2196 CHECK_ARITY(0);
2197 if ((ctxt->context->nodelist == NULL) ||
2198 (ctxt->context->node == NULL) ||
2199 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002200 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002201 }
2202 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2203 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002204 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002205 return;
2206 }
2207 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002208 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002209}
2210
2211/**
2212 * xmlXPathCountFunction:
2213 * @ctxt: the XPath Parser context
2214 *
2215 * Implement the count() XPath function
2216 */
2217void
2218xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2219 xmlXPathObjectPtr cur;
2220
2221 CHECK_ARITY(1);
2222 CHECK_TYPE(XPATH_NODESET);
2223 cur = valuePop(ctxt);
2224
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002225 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002226 xmlXPathFreeObject(cur);
2227}
2228
2229/**
2230 * xmlXPathIdFunction:
2231 * @ctxt: the XPath Parser context
2232 *
2233 * Implement the id() XPath function
2234 * The id function selects elements by their unique ID
2235 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2236 * then the result is the union of the result of applying id to the
2237 * string value of each of the nodes in the argument node-set. When the
2238 * argument to id is of any other type, the argument is converted to a
2239 * string as if by a call to the string function; the string is split
2240 * into a whitespace-separated list of tokens (whitespace is any sequence
2241 * of characters matching the production S); the result is a node-set
2242 * containing the elements in the same document as the context node that
2243 * have a unique ID equal to any of the tokens in the list.
2244 */
2245void
2246xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002247 const xmlChar *tokens;
2248 const xmlChar *cur;
2249 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002250 xmlAttrPtr attr;
2251 xmlNodePtr elem = NULL;
2252 xmlXPathObjectPtr ret, obj;
2253
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002254 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002255 obj = valuePop(ctxt);
2256 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2257 if (obj->type == XPATH_NODESET) {
2258 TODO /* ID function in case of NodeSet */
2259 }
2260 if (obj->type != XPATH_STRING) {
2261 valuePush(ctxt, obj);
2262 xmlXPathStringFunction(ctxt, 1);
2263 obj = valuePop(ctxt);
2264 if (obj->type != XPATH_STRING) {
2265 xmlXPathFreeObject(obj);
2266 return;
2267 }
2268 }
2269 tokens = obj->stringval;
2270
2271 ret = xmlXPathNewNodeSet(NULL);
2272 valuePush(ctxt, ret);
2273 if (tokens == NULL) {
2274 xmlXPathFreeObject(obj);
2275 return;
2276 }
2277
2278 cur = tokens;
2279
2280 while (IS_BLANK(*cur)) cur++;
2281 while (*cur != 0) {
2282 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2283 (*cur == '.') || (*cur == '-') ||
2284 (*cur == '_') || (*cur == ':') ||
2285 (IS_COMBINING(*cur)) ||
2286 (IS_EXTENDER(*cur)))
2287 cur++;
2288
2289 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2290
2291 ID = xmlStrndup(tokens, cur - tokens);
2292 attr = xmlGetID(ctxt->context->doc, ID);
2293 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002294 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002295 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2296 }
2297 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002298 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002299
2300 while (IS_BLANK(*cur)) cur++;
2301 tokens = cur;
2302 }
2303 xmlXPathFreeObject(obj);
2304 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002305}
2306
2307/**
2308 * xmlXPathLocalPartFunction:
2309 * @ctxt: the XPath Parser context
2310 *
2311 * Implement the local-part() XPath function
2312 * The local-part function returns a string containing the local part
2313 * of the name of the node in the argument node-set that is first in
2314 * document order. If the node-set is empty or the first node has no
2315 * name, an empty string is returned. If the argument is omitted it
2316 * defaults to the context node.
2317 */
2318void
2319xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2320 xmlXPathObjectPtr cur;
2321
2322 CHECK_ARITY(1);
2323 CHECK_TYPE(XPATH_NODESET);
2324 cur = valuePop(ctxt);
2325
2326 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002327 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002328 } else {
2329 int i = 0; /* Should be first in document order !!!!! */
2330 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2331 }
2332 xmlXPathFreeObject(cur);
2333}
2334
2335/**
2336 * xmlXPathNamespaceFunction:
2337 * @ctxt: the XPath Parser context
2338 *
2339 * Implement the namespace() XPath function
2340 * The namespace function returns a string containing the namespace URI
2341 * of the expanded name of the node in the argument node-set that is
2342 * first in document order. If the node-set is empty, the first node has
2343 * no name, or the expanded name has no namespace URI, an empty string
2344 * is returned. If the argument is omitted it defaults to the context node.
2345 */
2346void
2347xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2348 xmlXPathObjectPtr cur;
2349
Daniel Veillardb96e6431999-08-29 21:02:19 +00002350 if (nargs == 0) {
2351 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2352 nargs = 1;
2353 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002354 CHECK_ARITY(1);
2355 CHECK_TYPE(XPATH_NODESET);
2356 cur = valuePop(ctxt);
2357
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 {
2361 int i = 0; /* Should be first in document order !!!!! */
2362
2363 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002364 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002365 else
2366 valuePush(ctxt, xmlXPathNewString(
2367 cur->nodesetval->nodeTab[i]->ns->href));
2368 }
2369 xmlXPathFreeObject(cur);
2370}
2371
2372/**
2373 * xmlXPathNameFunction:
2374 * @ctxt: the XPath Parser context
2375 *
2376 * Implement the name() XPath function
2377 * The name function returns a string containing a QName representing
2378 * the name of the node in the argument node-set that is first in documenti
2379 * order. The QName must represent the name with respect to the namespace
2380 * declarations in effect on the node whose name is being represented.
2381 * Typically, this will be the form in which the name occurred in the XML
2382 * source. This need not be the case if there are namespace declarations
2383 * in effect on the node that associate multiple prefixes with the same
2384 * namespace. However, an implementation may include information about
2385 * the original prefix in its representation of nodes; in this case, an
2386 * implementation can ensure that the returned string is always the same
2387 * as the QName used in the XML source. If the argument it omitted it
2388 * defaults to the context node.
2389 * Libxml keep the original prefix so the "real qualified name" used is
2390 * returned.
2391 */
2392void
2393xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2394 xmlXPathObjectPtr cur;
2395
2396 CHECK_ARITY(1);
2397 CHECK_TYPE(XPATH_NODESET);
2398 cur = valuePop(ctxt);
2399
2400 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002401 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002402 } else {
2403 int i = 0; /* Should be first in document order !!!!! */
2404
2405 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2406 valuePush(ctxt, xmlXPathNewString(
2407 cur->nodesetval->nodeTab[i]->name));
2408
2409 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002410 char name[2000];
2411 sprintf(name, "%s:%s",
2412 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2413 (char *) cur->nodesetval->nodeTab[i]->name);
2414 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002415 }
2416 }
2417 xmlXPathFreeObject(cur);
2418}
2419
2420/**
2421 * xmlXPathStringFunction:
2422 * @ctxt: the XPath Parser context
2423 *
2424 * Implement the string() XPath function
2425 * he string function converts an object to a string as follows:
2426 * - A node-set is converted to a string by returning the value of
2427 * the node in the node-set that is first in document order.
2428 * If the node-set is empty, an empty string is returned.
2429 * - A number is converted to a string as follows
2430 * + NaN is converted to the string NaN
2431 * + positive zero is converted to the string 0
2432 * + negative zero is converted to the string 0
2433 * + positive infinity is converted to the string Infinity
2434 * + negative infinity is converted to the string -Infinity
2435 * + if the number is an integer, the number is represented in
2436 * decimal form as a Number with no decimal point and no leading
2437 * zeros, preceded by a minus sign (-) if the number is negative
2438 * + otherwise, the number is represented in decimal form as a
2439 * Number including a decimal point with at least one digit
2440 * before the decimal point and at least one digit after the
2441 * decimal point, preceded by a minus sign (-) if the number
2442 * is negative; there must be no leading zeros before the decimal
2443 * point apart possibly from the one required digit immediatelyi
2444 * before the decimal point; beyond the one required digit
2445 * after the decimal point there must be as many, but only as
2446 * many, more digits as are needed to uniquely distinguish the
2447 * number from all other IEEE 754 numeric values.
2448 * - The boolean false value is converted to the string false.
2449 * The boolean true value is converted to the string true.
2450 */
2451void
2452xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2453 xmlXPathObjectPtr cur;
2454
2455 CHECK_ARITY(1);
2456 cur = valuePop(ctxt);
2457 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2458 switch (cur->type) {
2459 case XPATH_NODESET:
2460 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002461 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002462 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002463 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002464 int i = 0; /* Should be first in document order !!!!! */
2465 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2466 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002467 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002468 }
2469 xmlXPathFreeObject(cur);
2470 return;
2471 case XPATH_STRING:
2472 valuePush(ctxt, cur);
2473 return;
2474 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002475 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2476 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002477 xmlXPathFreeObject(cur);
2478 return;
2479 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002480 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002481
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002482 if (isnan(cur->floatval))
2483 sprintf(buf, "NaN");
2484 else if (isinf(cur->floatval) > 0)
2485 sprintf(buf, "+Infinity");
2486 else if (isinf(cur->floatval) < 0)
2487 sprintf(buf, "-Infinity");
2488 else
2489 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002490 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002491 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002492 return;
2493 }
2494 }
2495 STRANGE
2496}
2497
2498/**
2499 * xmlXPathStringLengthFunction:
2500 * @ctxt: the XPath Parser context
2501 *
2502 * Implement the string-length() XPath function
2503 * The string-length returns the number of characters in the string
2504 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2505 * the context node converted to a string, in other words the value
2506 * of the context node.
2507 */
2508void
2509xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2510 xmlXPathObjectPtr cur;
2511
2512 if (nargs == 0) {
2513 if (ctxt->context->node == NULL) {
2514 valuePush(ctxt, xmlXPathNewFloat(0));
2515 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002516 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002517
2518 content = xmlNodeGetContent(ctxt->context->node);
2519 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002520 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002521 }
2522 return;
2523 }
2524 CHECK_ARITY(1);
2525 CHECK_TYPE(XPATH_STRING);
2526 cur = valuePop(ctxt);
2527 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2528 xmlXPathFreeObject(cur);
2529}
2530
2531/**
2532 * xmlXPathConcatFunction:
2533 * @ctxt: the XPath Parser context
2534 *
2535 * Implement the concat() XPath function
2536 * The concat function returns the concatenation of its arguments.
2537 */
2538void
2539xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2540 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002541 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002542
2543 if (nargs < 2) {
2544 CHECK_ARITY(2);
2545 }
2546
2547 cur = valuePop(ctxt);
2548 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2549 xmlXPathFreeObject(cur);
2550 return;
2551 }
2552 nargs--;
2553
2554 while (nargs > 0) {
2555 new = valuePop(ctxt);
2556 if ((new == NULL) || (new->type != XPATH_STRING)) {
2557 xmlXPathFreeObject(new);
2558 xmlXPathFreeObject(cur);
2559 ERROR(XPATH_INVALID_TYPE);
2560 }
2561 tmp = xmlStrcat(new->stringval, cur->stringval);
2562 new->stringval = cur->stringval;
2563 cur->stringval = tmp;
2564
2565 xmlXPathFreeObject(new);
2566 nargs--;
2567 }
2568 valuePush(ctxt, cur);
2569}
2570
2571/**
2572 * xmlXPathContainsFunction:
2573 * @ctxt: the XPath Parser context
2574 *
2575 * Implement the contains() XPath function
2576 * The contains function returns true if the first argument string
2577 * contains the second argument string, and otherwise returns false.
2578 */
2579void
2580xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2581 xmlXPathObjectPtr hay, needle;
2582
2583 CHECK_ARITY(2);
2584 CHECK_TYPE(XPATH_STRING);
2585 needle = valuePop(ctxt);
2586 hay = valuePop(ctxt);
2587 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2588 xmlXPathFreeObject(hay);
2589 xmlXPathFreeObject(needle);
2590 ERROR(XPATH_INVALID_TYPE);
2591 }
2592 if (xmlStrstr(hay->stringval, needle->stringval))
2593 valuePush(ctxt, xmlXPathNewBoolean(1));
2594 else
2595 valuePush(ctxt, xmlXPathNewBoolean(0));
2596 xmlXPathFreeObject(hay);
2597 xmlXPathFreeObject(needle);
2598}
2599
2600/**
2601 * xmlXPathStartsWithFunction:
2602 * @ctxt: the XPath Parser context
2603 *
2604 * Implement the starts-with() XPath function
2605 * The starts-with function returns true if the first argument string
2606 * starts with the second argument string, and otherwise returns false.
2607 */
2608void
2609xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2610 xmlXPathObjectPtr hay, needle;
2611 int n;
2612
2613 CHECK_ARITY(2);
2614 CHECK_TYPE(XPATH_STRING);
2615 needle = valuePop(ctxt);
2616 hay = valuePop(ctxt);
2617 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2618 xmlXPathFreeObject(hay);
2619 xmlXPathFreeObject(needle);
2620 ERROR(XPATH_INVALID_TYPE);
2621 }
2622 n = xmlStrlen(needle->stringval);
2623 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2624 valuePush(ctxt, xmlXPathNewBoolean(0));
2625 else
2626 valuePush(ctxt, xmlXPathNewBoolean(1));
2627 xmlXPathFreeObject(hay);
2628 xmlXPathFreeObject(needle);
2629}
2630
2631/**
2632 * xmlXPathSubstringFunction:
2633 * @ctxt: the XPath Parser context
2634 *
2635 * Implement the substring() XPath function
2636 * The substring function returns the substring of the first argument
2637 * starting at the position specified in the second argument with
2638 * length specified in the third argument. For example,
2639 * substring("12345",2,3) returns "234". If the third argument is not
2640 * specified, it returns the substring starting at the position specified
2641 * in the second argument and continuing to the end of the string. For
2642 * example, substring("12345",2) returns "2345". More precisely, each
2643 * character in the string (see [3.6 Strings]) is considered to have a
2644 * numeric position: the position of the first character is 1, the position
2645 * of the second character is 2 and so on. The returned substring contains
2646 * those characters for which the position of the character is greater than
2647 * or equal to the second argument and, if the third argument is specified,
2648 * less than the sum of the second and third arguments; the comparisons
2649 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2650 * - substring("12345", 1.5, 2.6) returns "234"
2651 * - substring("12345", 0, 3) returns "12"
2652 * - substring("12345", 0 div 0, 3) returns ""
2653 * - substring("12345", 1, 0 div 0) returns ""
2654 * - substring("12345", -42, 1 div 0) returns "12345"
2655 * - substring("12345", -1 div 0, 1 div 0) returns ""
2656 */
2657void
2658xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2659 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002660 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002661 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002662 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002663
2664 /*
2665 * Conformance needs to be checked !!!!!
2666 */
2667 if (nargs < 2) {
2668 CHECK_ARITY(2);
2669 }
2670 if (nargs > 3) {
2671 CHECK_ARITY(3);
2672 }
2673 if (nargs == 3) {
2674 CHECK_TYPE(XPATH_NUMBER);
2675 len = valuePop(ctxt);
2676 le = len->floatval;
2677 xmlXPathFreeObject(len);
2678 } else {
2679 le = 2000000000;
2680 }
2681 CHECK_TYPE(XPATH_NUMBER);
2682 start = valuePop(ctxt);
2683 in = start->floatval;
2684 xmlXPathFreeObject(start);
2685 CHECK_TYPE(XPATH_STRING);
2686 str = valuePop(ctxt);
2687 le += in;
2688
2689 /* integer index of the first char */
2690 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002691 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002692
2693 /* integer index of the last char */
2694 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002695 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002696
2697 /* back to a zero based len */
2698 i--;
2699 l--;
2700
2701 /* check against the string len */
2702 if (l > 1024) {
2703 l = xmlStrlen(str->stringval);
2704 }
2705 if (i < 0) {
2706 i = 0;
2707 }
2708
2709 /* number of chars to copy */
2710 l -= i;
2711
2712 ret = xmlStrsub(str->stringval, i, l);
2713 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002714 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002715 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002716 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002717 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002718 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002719 xmlXPathFreeObject(str);
2720}
2721
2722/**
2723 * xmlXPathSubstringBeforeFunction:
2724 * @ctxt: the XPath Parser context
2725 *
2726 * Implement the substring-before() XPath function
2727 * The substring-before function returns the substring of the first
2728 * argument string that precedes the first occurrence of the second
2729 * argument string in the first argument string, or the empty string
2730 * if the first argument string does not contain the second argument
2731 * string. For example, substring-before("1999/04/01","/") returns 1999.
2732 */
2733void
2734xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2735 CHECK_ARITY(2);
2736 TODO /* substring before */
2737}
2738
2739/**
2740 * xmlXPathSubstringAfterFunction:
2741 * @ctxt: the XPath Parser context
2742 *
2743 * Implement the substring-after() XPath function
2744 * The substring-after function returns the substring of the first
2745 * argument string that follows the first occurrence of the second
2746 * argument string in the first argument string, or the empty stringi
2747 * if the first argument string does not contain the second argument
2748 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2749 * and substring-after("1999/04/01","19") returns 99/04/01.
2750 */
2751void
2752xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2753 CHECK_ARITY(2);
2754 TODO /* substring after */
2755}
2756
2757/**
2758 * xmlXPathNormalizeFunction:
2759 * @ctxt: the XPath Parser context
2760 *
2761 * Implement the normalize() XPath function
2762 * The normalize function returns the argument string with white
2763 * space normalized by stripping leading and trailing whitespace
2764 * and replacing sequences of whitespace characters by a single
2765 * space. Whitespace characters are the same allowed by the S production
2766 * in XML. If the argument is omitted, it defaults to the context
2767 * node converted to a string, in other words the value of the context node.
2768 */
2769void
2770xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2771 CHECK_ARITY(1);
2772 TODO /* normalize isn't as boring as translate, but pretty much */
2773}
2774
2775/**
2776 * xmlXPathTranslateFunction:
2777 * @ctxt: the XPath Parser context
2778 *
2779 * Implement the translate() XPath function
2780 * The translate function returns the first argument string with
2781 * occurrences of characters in the second argument string replaced
2782 * by the character at the corresponding position in the third argument
2783 * string. For example, translate("bar","abc","ABC") returns the string
2784 * BAr. If there is a character in the second argument string with no
2785 * character at a corresponding position in the third argument string
2786 * (because the second argument string is longer than the third argument
2787 * string), then occurrences of that character in the first argument
2788 * string are removed. For example, translate("--aaa--","abc-","ABC")
2789 * returns "AAA". If a character occurs more than once in second
2790 * argument string, then the first occurrence determines the replacement
2791 * character. If the third argument string is longer than the second
2792 * argument string, then excess characters are ignored.
2793 */
2794void
2795xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2796 CHECK_ARITY(3);
2797 TODO /* translate is boring, waiting for UTF-8 representation too */
2798}
2799
2800/**
2801 * xmlXPathBooleanFunction:
2802 * @ctxt: the XPath Parser context
2803 *
2804 * Implement the boolean() XPath function
2805 * he boolean function converts its argument to a boolean as follows:
2806 * - a number is true if and only if it is neither positive or
2807 * negative zero nor NaN
2808 * - a node-set is true if and only if it is non-empty
2809 * - a string is true if and only if its length is non-zero
2810 */
2811void
2812xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2813 xmlXPathObjectPtr cur;
2814 int res = 0;
2815
2816 CHECK_ARITY(1);
2817 cur = valuePop(ctxt);
2818 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2819 switch (cur->type) {
2820 case XPATH_NODESET:
2821 if ((cur->nodesetval == NULL) ||
2822 (cur->nodesetval->nodeNr == 0)) res = 0;
2823 else
2824 res = 1;
2825 break;
2826 case XPATH_STRING:
2827 if ((cur->stringval == NULL) ||
2828 (cur->stringval[0] == 0)) res = 0;
2829 else
2830 res = 1;
2831 break;
2832 case XPATH_BOOLEAN:
2833 valuePush(ctxt, cur);
2834 return;
2835 case XPATH_NUMBER:
2836 if (cur->floatval) res = 1;
2837 break;
2838 default:
2839 STRANGE
2840 }
2841 xmlXPathFreeObject(cur);
2842 valuePush(ctxt, xmlXPathNewBoolean(res));
2843}
2844
2845/**
2846 * xmlXPathNotFunction:
2847 * @ctxt: the XPath Parser context
2848 *
2849 * Implement the not() XPath function
2850 * The not function returns true if its argument is false,
2851 * and false otherwise.
2852 */
2853void
2854xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2855 CHECK_ARITY(1);
2856 CHECK_TYPE(XPATH_BOOLEAN);
2857 ctxt->value->boolval = ! ctxt->value->boolval;
2858}
2859
2860/**
2861 * xmlXPathTrueFunction:
2862 * @ctxt: the XPath Parser context
2863 *
2864 * Implement the true() XPath function
2865 */
2866void
2867xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2868 CHECK_ARITY(0);
2869 valuePush(ctxt, xmlXPathNewBoolean(1));
2870}
2871
2872/**
2873 * xmlXPathFalseFunction:
2874 * @ctxt: the XPath Parser context
2875 *
2876 * Implement the false() XPath function
2877 */
2878void
2879xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2880 CHECK_ARITY(0);
2881 valuePush(ctxt, xmlXPathNewBoolean(0));
2882}
2883
2884/**
2885 * xmlXPathLangFunction:
2886 * @ctxt: the XPath Parser context
2887 *
2888 * Implement the lang() XPath function
2889 * The lang function returns true or false depending on whether the
2890 * language of the context node as specified by xml:lang attributes
2891 * is the same as or is a sublanguage of the language specified by
2892 * the argument string. The language of the context node is determined
2893 * by the value of the xml:lang attribute on the context node, or, if
2894 * the context node has no xml:lang attribute, by the value of the
2895 * xml:lang attribute on the nearest ancestor of the context node that
2896 * has an xml:lang attribute. If there is no such attribute, then lang
2897 * returns false. If there is such an attribute, then lang returns
2898 * true if the attribute value is equal to the argument ignoring case,
2899 * or if there is some suffix starting with - such that the attribute
2900 * value is equal to the argument ignoring that suffix of the attribute
2901 * value and ignoring case.
2902 */
2903void
2904xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002905 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002906 const xmlChar *theLang;
2907 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002908 int ret = 0;
2909 int i;
2910
2911 CHECK_ARITY(1);
2912 CHECK_TYPE(XPATH_STRING);
2913 val = valuePop(ctxt);
2914 lang = val->stringval;
2915 theLang = xmlNodeGetLang(ctxt->context->node);
2916 if ((theLang != NULL) && (lang != NULL)) {
2917 for (i = 0;lang[i] != 0;i++)
2918 if (toupper(lang[i]) != toupper(theLang[i]))
2919 goto not_equal;
2920 ret = 1;
2921 }
2922not_equal:
2923 xmlXPathFreeObject(val);
2924 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002925}
2926
2927/**
2928 * xmlXPathNumberFunction:
2929 * @ctxt: the XPath Parser context
2930 *
2931 * Implement the number() XPath function
2932 */
2933void
2934xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2935 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002936 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002937
2938 CHECK_ARITY(1);
2939 cur = valuePop(ctxt);
2940 switch (cur->type) {
2941 case XPATH_NODESET:
2942 valuePush(ctxt, cur);
2943 xmlXPathStringFunction(ctxt, 1);
2944 cur = valuePop(ctxt);
2945 case XPATH_STRING:
2946 res = xmlXPathStringEvalNumber(cur->stringval);
2947 valuePush(ctxt, xmlXPathNewFloat(res));
2948 xmlXPathFreeObject(cur);
2949 return;
2950 case XPATH_BOOLEAN:
2951 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2952 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2953 xmlXPathFreeObject(cur);
2954 return;
2955 case XPATH_NUMBER:
2956 valuePush(ctxt, cur);
2957 return;
2958 }
2959 STRANGE
2960}
2961
2962/**
2963 * xmlXPathSumFunction:
2964 * @ctxt: the XPath Parser context
2965 *
2966 * Implement the sum() XPath function
2967 * The sum function returns the sum of the values of the nodes in
2968 * the argument node-set.
2969 */
2970void
2971xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2972 CHECK_ARITY(1);
2973 TODO /* BUG Sum : don't understand the definition */
2974}
2975
2976/**
2977 * xmlXPathFloorFunction:
2978 * @ctxt: the XPath Parser context
2979 *
2980 * Implement the floor() XPath function
2981 * The floor function returns the largest (closest to positive infinity)
2982 * number that is not greater than the argument and that is an integer.
2983 */
2984void
2985xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2986 CHECK_ARITY(1);
2987 CHECK_TYPE(XPATH_NUMBER);
2988 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002989 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002990}
2991
2992/**
2993 * xmlXPathCeilingFunction:
2994 * @ctxt: the XPath Parser context
2995 *
2996 * Implement the ceiling() XPath function
2997 * The ceiling function returns the smallest (closest to negative infinity)
2998 * number that is not less than the argument and that is an integer.
2999 */
3000void
3001xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003002 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003003
3004 CHECK_ARITY(1);
3005 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003006 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003007 if (f != ctxt->value->floatval)
3008 ctxt->value->floatval = f + 1;
3009}
3010
3011/**
3012 * xmlXPathRoundFunction:
3013 * @ctxt: the XPath Parser context
3014 *
3015 * Implement the round() XPath function
3016 * The round function returns the number that is closest to the
3017 * argument and that is an integer. If there are two such numbers,
3018 * then the one that is even is returned.
3019 */
3020void
3021xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003022 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003023
3024 CHECK_ARITY(1);
3025 CHECK_TYPE(XPATH_NUMBER);
3026 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003027 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003028 if (ctxt->value->floatval < f + 0.5)
3029 ctxt->value->floatval = f;
3030 else if (ctxt->value->floatval == f + 0.5)
3031 ctxt->value->floatval = f; /* !!!! Not following the spec here */
3032 else
3033 ctxt->value->floatval = f + 1;
3034}
3035
3036/************************************************************************
3037 * *
3038 * The Parser *
3039 * *
3040 ************************************************************************/
3041
3042/*
3043 * a couple of forward declarations since we use a recursive call based
3044 * implementation.
3045 */
3046void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3047void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3048void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3049void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3050
3051/**
3052 * xmlXPathParseNCName:
3053 * @ctxt: the XPath Parser context
3054 *
3055 * parse an XML namespace non qualified name.
3056 *
3057 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3058 *
3059 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3060 * CombiningChar | Extender
3061 *
3062 * Returns the namespace name or NULL
3063 */
3064
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003065xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003066xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003067 const xmlChar *q;
3068 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003069
3070 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3071 q = NEXT;
3072
3073 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3074 (CUR == '.') || (CUR == '-') ||
3075 (CUR == '_') ||
3076 (IS_COMBINING(CUR)) ||
3077 (IS_EXTENDER(CUR)))
3078 NEXT;
3079
3080 ret = xmlStrndup(q, CUR_PTR - q);
3081
3082 return(ret);
3083}
3084
3085/**
3086 * xmlXPathParseQName:
3087 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003088 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003089 *
3090 * parse an XML qualified name
3091 *
3092 * [NS 5] QName ::= (Prefix ':')? LocalPart
3093 *
3094 * [NS 6] Prefix ::= NCName
3095 *
3096 * [NS 7] LocalPart ::= NCName
3097 *
3098 * Returns the function returns the local part, and prefix is updated
3099 * to get the Prefix if any.
3100 */
3101
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003102xmlChar *
3103xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3104 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003105
3106 *prefix = NULL;
3107 ret = xmlXPathParseNCName(ctxt);
3108 if (CUR == ':') {
3109 *prefix = ret;
3110 NEXT;
3111 ret = xmlXPathParseNCName(ctxt);
3112 }
3113 return(ret);
3114}
3115
3116/**
3117 * xmlXPathStringEvalNumber:
3118 * @str: A string to scan
3119 *
3120 * [30] Number ::= Digits ('.' Digits)?
3121 * | '.' Digits
3122 * [31] Digits ::= [0-9]+
3123 *
3124 * Parse and evaluate a Number in the string
3125 *
3126 * BUG: "1.' is not valid ... James promised correction
3127 * as Digits ('.' Digits?)?
3128 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003129 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003130 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003131double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003132xmlXPathStringEvalNumber(const xmlChar *str) {
3133 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003134 double ret = 0.0;
3135 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003136 int ok = 0;
3137
3138 while (*cur == ' ') cur++;
3139 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003140 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003141 }
3142 while ((*cur >= '0') && (*cur <= '9')) {
3143 ret = ret * 10 + (*cur - '0');
3144 ok = 1;
3145 cur++;
3146 }
3147 if (*cur == '.') {
3148 cur++;
3149 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003150 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003151 }
3152 while ((*cur >= '0') && (*cur <= '9')) {
3153 mult /= 10;
3154 ret = ret + (*cur - '0') * mult;
3155 cur++;
3156 }
3157 }
3158 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003159 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003160 return(ret);
3161}
3162
3163/**
3164 * xmlXPathEvalNumber:
3165 * @ctxt: the XPath Parser context
3166 *
3167 * [30] Number ::= Digits ('.' Digits)?
3168 * | '.' Digits
3169 * [31] Digits ::= [0-9]+
3170 *
3171 * Parse and evaluate a Number, then push it on the stack
3172 *
3173 * BUG: "1.' is not valid ... James promised correction
3174 * as Digits ('.' Digits?)?
3175 */
3176void
3177xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003178 double ret = 0.0;
3179 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003180 int ok = 0;
3181
3182 CHECK_ERROR;
3183 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3184 ERROR(XPATH_NUMBER_ERROR);
3185 }
3186 while ((CUR >= '0') && (CUR <= '9')) {
3187 ret = ret * 10 + (CUR - '0');
3188 ok = 1;
3189 NEXT;
3190 }
3191 if (CUR == '.') {
3192 NEXT;
3193 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3194 ERROR(XPATH_NUMBER_ERROR);
3195 }
3196 while ((CUR >= '0') && (CUR <= '9')) {
3197 mult /= 10;
3198 ret = ret + (CUR - '0') * mult;
3199 NEXT;
3200 }
3201 }
3202 valuePush(ctxt, xmlXPathNewFloat(ret));
3203}
3204
3205/**
3206 * xmlXPathEvalLiteral:
3207 * @ctxt: the XPath Parser context
3208 *
3209 * Parse a Literal and push it on the stack.
3210 *
3211 * [29] Literal ::= '"' [^"]* '"'
3212 * | "'" [^']* "'"
3213 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003214 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003215 */
3216void
3217xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003218 const xmlChar *q;
3219 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003220
3221 if (CUR == '"') {
3222 NEXT;
3223 q = CUR_PTR;
3224 while ((IS_CHAR(CUR)) && (CUR != '"'))
3225 NEXT;
3226 if (!IS_CHAR(CUR)) {
3227 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3228 } else {
3229 ret = xmlStrndup(q, CUR_PTR - q);
3230 NEXT;
3231 }
3232 } else if (CUR == '\'') {
3233 NEXT;
3234 q = CUR_PTR;
3235 while ((IS_CHAR(CUR)) && (CUR != '\''))
3236 NEXT;
3237 if (!IS_CHAR(CUR)) {
3238 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3239 } else {
3240 ret = xmlStrndup(q, CUR_PTR - q);
3241 NEXT;
3242 }
3243 } else {
3244 ERROR(XPATH_START_LITERAL_ERROR);
3245 }
3246 if (ret == NULL) return;
3247 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003248 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003249}
3250
3251/**
3252 * xmlXPathEvalVariableReference:
3253 * @ctxt: the XPath Parser context
3254 *
3255 * Parse a VariableReference, evaluate it and push it on the stack.
3256 *
3257 * The variable bindings consist of a mapping from variable names
3258 * to variable values. The value of a variable is an object, which
3259 * of any of the types that are possible for the value of an expression,
3260 * and may also be of additional types not specified here.
3261 *
3262 * Early evaluation is possible since:
3263 * The variable bindings [...] used to evaluate a subexpression are
3264 * always the same as those used to evaluate the containing expression.
3265 *
3266 * [36] VariableReference ::= '$' QName
3267 */
3268void
3269xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003270 xmlChar *name;
3271 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003272 xmlXPathObjectPtr value;
3273
3274 if (CUR != '$') {
3275 ERROR(XPATH_VARIABLE_REF_ERROR);
3276 }
3277 name = xmlXPathParseQName(ctxt, &prefix);
3278 if (name == NULL) {
3279 ERROR(XPATH_VARIABLE_REF_ERROR);
3280 }
3281 value = xmlXPathVariablelookup(ctxt, prefix, name);
3282 if (value == NULL) {
3283 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3284 }
3285 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003286 if (prefix != NULL) xmlFree(prefix);
3287 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003288}
3289
3290
3291/**
3292 * xmlXPathFunctionLookup:
3293 * @ctxt: the XPath Parser context
3294 * @name: a name string
3295 *
3296 * Search for a function of the given name
3297 *
3298 * [35] FunctionName ::= QName - NodeType
3299 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003300 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003301 *
3302 * Returns the xmlXPathFunction if found, or NULL otherwise
3303 */
3304xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003305xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003306 switch (name[0]) {
3307 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003308 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003309 return(xmlXPathBooleanFunction);
3310 break;
3311 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003312 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003313 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003314 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003315 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003316 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003317 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003318 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003319 return(xmlXPathContainsFunction);
3320 break;
3321 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003322 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003323 return(xmlXPathIdFunction);
3324 break;
3325 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003326 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003327 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003328 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003329 return(xmlXPathFloorFunction);
3330 break;
3331 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003332 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003333 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003334 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003335 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003336 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003337 return(xmlXPathLocalPartFunction);
3338 break;
3339 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003340 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003341 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003342 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003343 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003344 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003345 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003346 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3347 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003348 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003349 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003350 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003351 return(xmlXPathNumberFunction);
3352 break;
3353 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003354 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003355 return(xmlXPathPositionFunction);
3356 break;
3357 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003358 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003359 return(xmlXPathRoundFunction);
3360 break;
3361 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003362 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003363 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003364 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003365 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003366 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003367 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003368 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003369 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003370 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003371 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003372 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003373 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003374 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003375 return(xmlXPathSumFunction);
3376 break;
3377 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003378 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003379 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003380 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003381 return(xmlXPathTranslateFunction);
3382 break;
3383 }
3384 return(NULL);
3385}
3386
3387/**
3388 * xmlXPathEvalLocationPathName:
3389 * @ctxt: the XPath Parser context
3390 * @name: a name string
3391 *
3392 * Various names in the beginning of a LocationPath expression
3393 * indicate whether that's an Axis, a node type,
3394 *
3395 * [6] AxisName ::= 'ancestor'
3396 * | 'ancestor-or-self'
3397 * | 'attribute'
3398 * | 'child'
3399 * | 'descendant'
3400 * | 'descendant-or-self'
3401 * | 'following'
3402 * | 'following-sibling'
3403 * | 'namespace'
3404 * | 'parent'
3405 * | 'preceding'
3406 * | 'preceding-sibling'
3407 * | 'self'
3408 * [38] NodeType ::= 'comment'
3409 * | 'text'
3410 * | 'processing-instruction'
3411 * | 'node'
3412 */
3413int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003414xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003415 switch (name[0]) {
3416 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003417 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3418 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3419 return(AXIS_ANCESTOR_OR_SELF);
3420 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003421 break;
3422 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003423 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3424 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003425 break;
3426 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003427 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3428 return(AXIS_DESCENDANT);
3429 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3430 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003431 break;
3432 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003433 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3434 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3435 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003436 break;
3437 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003438 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3439 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003440 break;
3441 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003442 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3443 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3444 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3445 return(AXIS_PRECEDING_SIBLING);
3446 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3447 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003448 break;
3449 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003450 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003451 break;
3452 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003453 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003454 break;
3455 }
3456 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3457 return(0);
3458}
3459
3460/**
3461 * xmlXPathEvalFunctionCall:
3462 * @ctxt: the XPath Parser context
3463 *
3464 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3465 * [17] Argument ::= Expr
3466 *
3467 * Parse and evaluate a function call, the evaluation of all arguments are
3468 * pushed on the stack
3469 */
3470void
3471xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003472 xmlChar *name;
3473 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003474 xmlXPathFunction func;
3475 int nbargs = 0;
3476
3477 name = xmlXPathParseQName(ctxt, &prefix);
3478 if (name == NULL) {
3479 ERROR(XPATH_EXPR_ERROR);
3480 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003481 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003482 func = xmlXPathIsFunction(ctxt, name);
3483 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003484 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003485 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3486 }
3487#ifdef DEBUG_EXPR
3488 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3489#endif
3490
3491 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003492 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003493 ERROR(XPATH_EXPR_ERROR);
3494 }
3495 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003496 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003497
3498 while (CUR != ')') {
3499 xmlXPathEvalExpr(ctxt);
3500 nbargs++;
3501 if (CUR == ')') break;
3502 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003503 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003504 ERROR(XPATH_EXPR_ERROR);
3505 }
3506 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003507 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003508 }
3509 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003510 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003511 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003512 func(ctxt, nbargs);
3513}
3514
3515/**
3516 * xmlXPathEvalPrimaryExpr:
3517 * @ctxt: the XPath Parser context
3518 *
3519 * [15] PrimaryExpr ::= VariableReference
3520 * | '(' Expr ')'
3521 * | Literal
3522 * | Number
3523 * | FunctionCall
3524 *
3525 * Parse and evaluate a primary expression, then push the result on the stack
3526 */
3527void
3528xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003529 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003530 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3531 else if (CUR == '(') {
3532 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003533 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003534 xmlXPathEvalExpr(ctxt);
3535 if (CUR != ')') {
3536 ERROR(XPATH_EXPR_ERROR);
3537 }
3538 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003539 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003540 } else if (IS_DIGIT(CUR)) {
3541 xmlXPathEvalNumber(ctxt);
3542 } else if ((CUR == '\'') || (CUR == '"')) {
3543 xmlXPathEvalLiteral(ctxt);
3544 } else {
3545 xmlXPathEvalFunctionCall(ctxt);
3546 }
3547}
3548
3549/**
3550 * xmlXPathEvalFilterExpr:
3551 * @ctxt: the XPath Parser context
3552 *
3553 * [20] FilterExpr ::= PrimaryExpr
3554 * | FilterExpr Predicate
3555 *
3556 * Parse and evaluate a filter expression, then push the result on the stack
3557 * Square brackets are used to filter expressions in the same way that
3558 * they are used in location paths. It is an error if the expression to
3559 * be filtered does not evaluate to a node-set. The context node list
3560 * used for evaluating the expression in square brackets is the node-set
3561 * to be filtered listed in document order.
3562 */
3563
3564void
3565xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3566 /****
3567 xmlNodeSetPtr oldset = NULL;
3568 xmlXPathObjectPtr arg;
3569 ****/
3570
3571 xmlXPathEvalPrimaryExpr(ctxt);
3572 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003573 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003574
3575 if (CUR != '[') return;
3576
3577 CHECK_TYPE(XPATH_NODESET);
3578
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003579 while (CUR == '[') {
3580 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003581 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003582 }
3583
3584
3585}
3586
3587/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003588 * xmlXPathScanName:
3589 * @ctxt: the XPath Parser context
3590 *
3591 * Trickery: parse an XML name but without consuming the input flow
3592 * Needed for rollback cases.
3593 *
3594 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3595 * CombiningChar | Extender
3596 *
3597 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3598 *
3599 * [6] Names ::= Name (S Name)*
3600 *
3601 * Returns the Name parsed or NULL
3602 */
3603
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003604xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003605xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003606 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003607 int len = 0;
3608
Daniel Veillard00fdf371999-10-08 09:40:39 +00003609 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003610 if (!IS_LETTER(CUR) && (CUR != '_') &&
3611 (CUR != ':')) {
3612 return(NULL);
3613 }
3614
3615 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3616 (NXT(len) == '.') || (NXT(len) == '-') ||
3617 (NXT(len) == '_') || (NXT(len) == ':') ||
3618 (IS_COMBINING(NXT(len))) ||
3619 (IS_EXTENDER(NXT(len)))) {
3620 buf[len] = NXT(len);
3621 len++;
3622 if (len >= XML_MAX_NAMELEN) {
3623 fprintf(stderr,
3624 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3625 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3626 (NXT(len) == '.') || (NXT(len) == '-') ||
3627 (NXT(len) == '_') || (NXT(len) == ':') ||
3628 (IS_COMBINING(NXT(len))) ||
3629 (IS_EXTENDER(NXT(len))))
3630 len++;
3631 break;
3632 }
3633 }
3634 return(xmlStrndup(buf, len));
3635}
3636
3637/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003638 * xmlXPathEvalPathExpr:
3639 * @ctxt: the XPath Parser context
3640 *
3641 * [19] PathExpr ::= LocationPath
3642 * | FilterExpr
3643 * | FilterExpr '/' RelativeLocationPath
3644 * | FilterExpr '//' RelativeLocationPath
3645 *
3646 * Parse and evaluate a path expression, then push the result on the stack
3647 * The / operator and // operators combine an arbitrary expression
3648 * and a relative location path. It is an error if the expression
3649 * does not evaluate to a node-set.
3650 * The / operator does composition in the same way as when / is
3651 * used in a location path. As in location paths, // is short for
3652 * /descendant-or-self::node()/.
3653 */
3654
3655void
3656xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3657 xmlNodeSetPtr newset = NULL;
3658
Daniel Veillard00fdf371999-10-08 09:40:39 +00003659 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003660 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3661 (CUR == '\'') || (CUR == '"')) {
3662 xmlXPathEvalFilterExpr(ctxt);
3663 CHECK_ERROR;
3664 if ((CUR == '/') && (NXT(1) == '/')) {
3665 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003666 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003667 if (ctxt->context->nodelist == NULL) {
3668 STRANGE
3669 xmlXPathRoot(ctxt);
3670 }
3671 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3672 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3673 if (ctxt->context->nodelist != NULL)
3674 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3675 ctxt->context->nodelist = newset;
3676 ctxt->context->node = NULL;
3677 xmlXPathEvalRelativeLocationPath(ctxt);
3678 } else if (CUR == '/') {
3679 xmlXPathEvalRelativeLocationPath(ctxt);
3680 }
3681 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003682 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003683 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003684
3685 name = xmlXPathScanName(ctxt);
3686 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3687 xmlXPathEvalLocationPath(ctxt);
3688 else
3689 xmlXPathEvalFilterExpr(ctxt);
3690 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003691 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003692 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003693 if (ctxt->context->nodelist != NULL)
3694 valuePush(ctxt, xmlXPathNewNodeSetList(ctxt->context->nodelist));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003695}
3696
3697/**
3698 * xmlXPathEvalUnionExpr:
3699 * @ctxt: the XPath Parser context
3700 *
3701 * [18] UnionExpr ::= PathExpr
3702 * | UnionExpr '|' PathExpr
3703 *
3704 * Parse and evaluate an union expression, then push the result on the stack
3705 */
3706
3707void
3708xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3709 xmlXPathEvalPathExpr(ctxt);
3710 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003711 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003712 if (CUR == '|') {
3713 xmlNodeSetPtr old = ctxt->context->nodelist;
3714
Daniel Veillard00fdf371999-10-08 09:40:39 +00003715 NEXT;
3716 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003717 xmlXPathEvalPathExpr(ctxt);
3718
3719 if (ctxt->context->nodelist == NULL)
3720 ctxt->context->nodelist = old;
3721 else {
3722 ctxt->context->nodelist =
3723 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3724 xmlXPathFreeNodeSet(old);
3725 }
3726 }
3727}
3728
3729/**
3730 * xmlXPathEvalUnaryExpr:
3731 * @ctxt: the XPath Parser context
3732 *
3733 * [27] UnaryExpr ::= UnionExpr
3734 * | '-' UnaryExpr
3735 *
3736 * Parse and evaluate an unary expression, then push the result on the stack
3737 */
3738
3739void
3740xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3741 int minus = 0;
3742
Daniel Veillard00fdf371999-10-08 09:40:39 +00003743 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003744 if (CUR == '-') {
3745 minus = 1;
3746 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003747 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003748 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003749 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003750 CHECK_ERROR;
3751 if (minus) {
3752 xmlXPathValueFlipSign(ctxt);
3753 }
3754}
3755
3756/**
3757 * xmlXPathEvalMultiplicativeExpr:
3758 * @ctxt: the XPath Parser context
3759 *
3760 * [26] MultiplicativeExpr ::= UnaryExpr
3761 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3762 * | MultiplicativeExpr 'div' UnaryExpr
3763 * | MultiplicativeExpr 'mod' UnaryExpr
3764 * [34] MultiplyOperator ::= '*'
3765 *
3766 * Parse and evaluate an Additive expression, then push the result on the stack
3767 */
3768
3769void
3770xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3771 xmlXPathEvalUnaryExpr(ctxt);
3772 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003773 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003774 while ((CUR == '*') ||
3775 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3776 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3777 int op = -1;
3778
3779 if (CUR == '*') {
3780 op = 0;
3781 NEXT;
3782 } else if (CUR == 'd') {
3783 op = 1;
3784 SKIP(3);
3785 } else if (CUR == 'm') {
3786 op = 2;
3787 SKIP(3);
3788 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003789 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003790 xmlXPathEvalUnaryExpr(ctxt);
3791 CHECK_ERROR;
3792 switch (op) {
3793 case 0:
3794 xmlXPathMultValues(ctxt);
3795 break;
3796 case 1:
3797 xmlXPathDivValues(ctxt);
3798 break;
3799 case 2:
3800 xmlXPathModValues(ctxt);
3801 break;
3802 }
3803 }
3804}
3805
3806/**
3807 * xmlXPathEvalAdditiveExpr:
3808 * @ctxt: the XPath Parser context
3809 *
3810 * [25] AdditiveExpr ::= MultiplicativeExpr
3811 * | AdditiveExpr '+' MultiplicativeExpr
3812 * | AdditiveExpr '-' MultiplicativeExpr
3813 *
3814 * Parse and evaluate an Additive expression, then push the result on the stack
3815 */
3816
3817void
3818xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3819 xmlXPathEvalMultiplicativeExpr(ctxt);
3820 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003821 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003822 while ((CUR == '+') || (CUR == '-')) {
3823 int plus;
3824
3825 if (CUR == '+') plus = 1;
3826 else plus = 0;
3827 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003828 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003829 xmlXPathEvalMultiplicativeExpr(ctxt);
3830 CHECK_ERROR;
3831 if (plus) xmlXPathAddValues(ctxt);
3832 else xmlXPathSubValues(ctxt);
3833 }
3834}
3835
3836/**
3837 * xmlXPathEvalRelationalExpr:
3838 * @ctxt: the XPath Parser context
3839 *
3840 * [24] RelationalExpr ::= AdditiveExpr
3841 * | RelationalExpr '<' AdditiveExpr
3842 * | RelationalExpr '>' AdditiveExpr
3843 * | RelationalExpr '<=' AdditiveExpr
3844 * | RelationalExpr '>=' AdditiveExpr
3845 *
3846 * A <= B > C is allowed ? Answer from James, yes with
3847 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3848 * which is basically what got implemented.
3849 *
3850 * Parse and evaluate a Relational expression, then push the result
3851 * on the stack
3852 */
3853
3854void
3855xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3856 xmlXPathEvalAdditiveExpr(ctxt);
3857 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003858 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003859 while ((CUR == '<') ||
3860 (CUR == '>') ||
3861 ((CUR == '<') && (NXT(1) == '=')) ||
3862 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003863 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003864
3865 if (CUR == '<') inf = 1;
3866 else inf = 0;
3867 if (NXT(1) == '=') strict = 0;
3868 else strict = 1;
3869 NEXT;
3870 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003871 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003872 xmlXPathEvalAdditiveExpr(ctxt);
3873 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003874 ret = xmlXPathCompareValues(ctxt, inf, strict);
3875 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003876 }
3877}
3878
3879/**
3880 * xmlXPathEvalEqualityExpr:
3881 * @ctxt: the XPath Parser context
3882 *
3883 * [23] EqualityExpr ::= RelationalExpr
3884 * | EqualityExpr '=' RelationalExpr
3885 * | EqualityExpr '!=' RelationalExpr
3886 *
3887 * A != B != C is allowed ? Answer from James, yes with
3888 * (RelationalExpr = RelationalExpr) = RelationalExpr
3889 * (RelationalExpr != RelationalExpr) != RelationalExpr
3890 * which is basically what got implemented.
3891 *
3892 * Parse and evaluate an Equality expression, then push the result on the stack
3893 *
3894 */
3895void
3896xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3897 xmlXPathEvalRelationalExpr(ctxt);
3898 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003899 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003900 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003901 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003902 int eq, equal;
3903
3904 if (CUR == '=') eq = 1;
3905 else eq = 0;
3906 NEXT;
3907 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003908 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003909 xmlXPathEvalRelationalExpr(ctxt);
3910 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003911 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003912 if (eq) res = xmlXPathNewBoolean(equal);
3913 else res = xmlXPathNewBoolean(!equal);
3914 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003915 }
3916}
3917
3918/**
3919 * xmlXPathEvalAndExpr:
3920 * @ctxt: the XPath Parser context
3921 *
3922 * [22] AndExpr ::= EqualityExpr
3923 * | AndExpr 'and' EqualityExpr
3924 *
3925 * Parse and evaluate an AND expression, then push the result on the stack
3926 *
3927 */
3928void
3929xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3930 xmlXPathEvalEqualityExpr(ctxt);
3931 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003932 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003933 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3934 xmlXPathObjectPtr arg1, arg2;
3935
3936 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003937 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003938 xmlXPathEvalEqualityExpr(ctxt);
3939 CHECK_ERROR;
3940 arg2 = valuePop(ctxt);
3941 arg1 = valuePop(ctxt);
3942 arg1->boolval &= arg2->boolval;
3943 valuePush(ctxt, arg1);
3944 xmlXPathFreeObject(arg2);
3945 }
3946}
3947
3948/**
3949 * xmlXPathEvalExpr:
3950 * @ctxt: the XPath Parser context
3951 *
3952 * [14] Expr ::= OrExpr
3953 * [21] OrExpr ::= AndExpr
3954 * | OrExpr 'or' AndExpr
3955 *
3956 * Parse and evaluate an expression, then push the result on the stack
3957 *
3958 */
3959void
3960xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3961 xmlXPathEvalAndExpr(ctxt);
3962 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003963 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003964 while ((CUR == 'o') && (NXT(1) == 'r')) {
3965 xmlXPathObjectPtr arg1, arg2;
3966
3967 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003968 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003969 xmlXPathEvalAndExpr(ctxt);
3970 CHECK_ERROR;
3971 arg2 = valuePop(ctxt);
3972 arg1 = valuePop(ctxt);
3973 arg1->boolval |= arg2->boolval;
3974 valuePush(ctxt, arg1);
3975 xmlXPathFreeObject(arg2);
3976 }
3977}
3978
3979/**
3980 * xmlXPathEvaluatePredicateResult:
3981 * @ctxt: the XPath Parser context
3982 * @res: the Predicate Expression evaluation result
3983 * @index: index of the current node in the current list
3984 *
3985 * Evaluate a predicate result for the current node.
3986 * A PredicateExpr is evaluated by evaluating the Expr and converting
3987 * the result to a boolean. If the result is a number, the result will
3988 * be converted to true if the number is equal to the position of the
3989 * context node in the context node list (as returned by the position
3990 * function) and will be converted to false otherwise; if the result
3991 * is not a number, then the result will be converted as if by a call
3992 * to the boolean function.
3993 */
3994int
3995xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3996 xmlXPathObjectPtr res, int index) {
3997 if (res == NULL) return(0);
3998 switch (res->type) {
3999 case XPATH_BOOLEAN:
4000 return(res->boolval);
4001 case XPATH_NUMBER:
4002 return(res->floatval == index);
4003 case XPATH_NODESET:
4004 return(res->nodesetval->nodeNr != 0);
4005 case XPATH_STRING:
4006 return((res->stringval != NULL) &&
4007 (xmlStrlen(res->stringval) != 0));
4008 default:
4009 STRANGE
4010 }
4011 return(0);
4012}
4013
4014/**
4015 * xmlXPathEvalPredicate:
4016 * @ctxt: the XPath Parser context
4017 *
4018 * [8] Predicate ::= '[' PredicateExpr ']'
4019 * [9] PredicateExpr ::= Expr
4020 *
4021 * Parse and evaluate a predicate for all the elements of the
4022 * current node list. Then refine the list by removing all
4023 * nodes where the predicate is false.
4024 */
4025void
4026xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004027 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004028 xmlXPathObjectPtr res;
4029 xmlNodeSetPtr newset = NULL;
4030 int i;
4031
Daniel Veillard00fdf371999-10-08 09:40:39 +00004032 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004033 if (CUR != '[') {
4034 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4035 }
4036 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004037 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004038 if ((ctxt->context->nodelist == NULL) ||
4039 (ctxt->context->nodelist->nodeNr == 0)) {
4040 ctxt->context->node = NULL;
4041 xmlXPathEvalExpr(ctxt);
4042 CHECK_ERROR;
4043 res = valuePop(ctxt);
4044 if (res != NULL)
4045 xmlXPathFreeObject(res);
4046 } else {
4047 cur = ctxt->cur;
4048 newset = xmlXPathNodeSetCreate(NULL);
4049 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
4050 ctxt->cur = cur;
4051 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
4052 xmlXPathEvalExpr(ctxt);
4053 CHECK_ERROR;
4054 res = valuePop(ctxt);
4055 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
4056 xmlXPathNodeSetAdd(newset,
4057 ctxt->context->nodelist->nodeTab[i]);
4058 if (res != NULL)
4059 xmlXPathFreeObject(res);
4060 }
4061 if (ctxt->context->nodelist != NULL)
4062 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4063 ctxt->context->nodelist = newset;
4064 ctxt->context->node = NULL;
4065 }
4066 if (CUR != ']') {
4067 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4068 }
4069 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004070 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004071#ifdef DEBUG_STEP
4072 fprintf(xmlXPathDebug, "After predicate : ");
4073 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4074#endif
4075}
4076
4077/**
4078 * xmlXPathEvalBasis:
4079 * @ctxt: the XPath Parser context
4080 *
4081 * [5] Basis ::= AxisName '::' NodeTest
4082 * | AbbreviatedBasis
4083 * [13] AbbreviatedBasis ::= NodeTest
4084 * | '@' NodeTest
4085 * [7] NodeTest ::= WildcardName
4086 * | NodeType '(' ')'
4087 * | 'processing-instruction' '(' Literal ')'
4088 * [37] WildcardName ::= '*'
4089 * | NCName ':' '*'
4090 * | QName
4091 *
4092 * Evaluate one step in a Location Path
4093 */
4094void
4095xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004096 xmlChar *name = NULL;
4097 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004098 int type = 0;
4099 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4100 int nodetest = NODE_TEST_NONE;
4101 int nodetype = 0;
4102 xmlNodeSetPtr newset = NULL;
4103
4104 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004105 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004106 axis = AXIS_ATTRIBUTE;
4107 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004108 } else if (CUR == '*') {
4109 NEXT;
4110 nodetest = NODE_TEST_ALL;
4111 } else {
4112 name = xmlXPathParseNCName(ctxt);
4113 if (name == NULL) {
4114 ERROR(XPATH_EXPR_ERROR);
4115 }
4116 type = xmlXPathGetNameType(ctxt, name);
4117 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004118 case IS_FUNCTION: {
4119 xmlXPathFunction func;
4120 int nbargs = 0;
4121 xmlXPathObjectPtr top;
4122
4123 top = ctxt->value;
4124 func = xmlXPathIsFunction(ctxt, name);
4125 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004126 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004127 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4128 }
4129#ifdef DEBUG_EXPR
4130 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4131#endif
4132
4133 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004134 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004135 ERROR(XPATH_EXPR_ERROR);
4136 }
4137 NEXT;
4138
4139 while (CUR != ')') {
4140 xmlXPathEvalExpr(ctxt);
4141 nbargs++;
4142 if (CUR == ')') break;
4143 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004144 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004145 ERROR(XPATH_EXPR_ERROR);
4146 }
4147 NEXT;
4148 }
4149 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004150 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004151 func(ctxt, nbargs);
4152 if ((ctxt->value != top) &&
4153 (ctxt->value != NULL) &&
4154 (ctxt->value->type == XPATH_NODESET)) {
4155 xmlXPathObjectPtr cur;
4156
4157 cur = valuePop(ctxt);
4158 ctxt->context->nodelist = cur->nodesetval;
4159 ctxt->context->node = NULL;
4160 cur->nodesetval = NULL;
4161 xmlXPathFreeObject(cur);
4162 }
4163 return;
4164 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004165 /*
4166 * Simple case: no axis seach all given node types.
4167 */
4168 case NODE_TYPE_COMMENT:
4169 if ((CUR != '(') || (NXT(1) != ')')) break;
4170 SKIP(2);
4171 nodetest = NODE_TEST_TYPE;
4172 nodetype = XML_COMMENT_NODE;
4173 goto search_nodes;
4174 case NODE_TYPE_TEXT:
4175 if ((CUR != '(') || (NXT(1) != ')')) break;
4176 SKIP(2);
4177 nodetest = NODE_TEST_TYPE;
4178 nodetype = XML_TEXT_NODE;
4179 goto search_nodes;
4180 case NODE_TYPE_NODE:
4181 if ((CUR != '(') || (NXT(1) != ')')) {
4182 nodetest = NODE_TEST_NAME;
4183 break;
4184 }
4185 SKIP(2);
4186 nodetest = NODE_TEST_TYPE;
4187 nodetype = XML_ELEMENT_NODE;
4188 goto search_nodes;
4189 case NODE_TYPE_PI:
4190 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004191 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004192 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004193 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004194 xmlXPathObjectPtr cur;
4195
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004196 /*
4197 * Specific case: search a PI by name.
4198 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004199 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004200 nodetest = NODE_TEST_PI;
4201 xmlXPathEvalLiteral(ctxt);
4202 CHECK_ERROR;
4203 if (CUR != ')')
4204 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004205 NEXT;
4206 xmlXPathStringFunction(ctxt, 1);
4207 CHECK_ERROR;
4208 cur = valuePop(ctxt);
4209 name = xmlStrdup(cur->stringval);
4210 xmlXPathFreeObject(cur);
4211 } else
4212 SKIP(2);
4213 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004214 goto search_nodes;
4215
4216 /*
4217 * Handling of the compund form: got the axis.
4218 */
4219 case AXIS_ANCESTOR:
4220 case AXIS_ANCESTOR_OR_SELF:
4221 case AXIS_ATTRIBUTE:
4222 case AXIS_CHILD:
4223 case AXIS_DESCENDANT:
4224 case AXIS_DESCENDANT_OR_SELF:
4225 case AXIS_FOLLOWING:
4226 case AXIS_FOLLOWING_SIBLING:
4227 case AXIS_NAMESPACE:
4228 case AXIS_PARENT:
4229 case AXIS_PRECEDING:
4230 case AXIS_PRECEDING_SIBLING:
4231 case AXIS_SELF:
4232 if ((CUR != ':') || (NXT(1) != ':')) {
4233 nodetest = NODE_TEST_NAME;
4234 break;
4235 }
4236 SKIP(2);
4237 axis = type;
4238 break;
4239
4240 /*
4241 * Default: abbreviated syntax the axis is AXIS_CHILD
4242 */
4243 default:
4244 nodetest = NODE_TEST_NAME;
4245 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004246parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004247 if (nodetest == NODE_TEST_NONE) {
4248 if (CUR == '*') {
4249 NEXT;
4250 nodetest = NODE_TEST_ALL;
4251 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004252 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004253 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004254 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004255 if (name == NULL) {
4256 ERROR(XPATH_EXPR_ERROR);
4257 }
4258 type = xmlXPathGetNameType(ctxt, name);
4259 switch (type) {
4260 /*
4261 * Simple case: no axis seach all given node types.
4262 */
4263 case NODE_TYPE_COMMENT:
4264 if ((CUR != '(') || (NXT(1) != ')')) break;
4265 SKIP(2);
4266 nodetest = NODE_TEST_TYPE;
4267 nodetype = XML_COMMENT_NODE;
4268 goto search_nodes;
4269 case NODE_TYPE_TEXT:
4270 if ((CUR != '(') || (NXT(1) != ')')) break;
4271 SKIP(2);
4272 nodetest = NODE_TEST_TYPE;
4273 nodetype = XML_TEXT_NODE;
4274 goto search_nodes;
4275 case NODE_TYPE_NODE:
4276 if ((CUR != '(') || (NXT(1) != ')')) {
4277 nodetest = NODE_TEST_NAME;
4278 break;
4279 }
4280 SKIP(2);
4281 nodetest = NODE_TEST_TYPE;
4282 nodetype = XML_ELEMENT_NODE;
4283 goto search_nodes;
4284 case NODE_TYPE_PI:
4285 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004286 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004287 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004288 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004289 xmlXPathObjectPtr cur;
4290
Daniel Veillardb05deb71999-08-10 19:04:08 +00004291 /*
4292 * Specific case: search a PI by name.
4293 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004294 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004295 nodetest = NODE_TEST_PI;
4296 xmlXPathEvalLiteral(ctxt);
4297 CHECK_ERROR;
4298 if (CUR != ')')
4299 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004300 NEXT;
4301 xmlXPathStringFunction(ctxt, 1);
4302 CHECK_ERROR;
4303 cur = valuePop(ctxt);
4304 name = xmlStrdup(cur->stringval);
4305 xmlXPathFreeObject(cur);
4306 } else
4307 SKIP(2);
4308 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004309 goto search_nodes;
4310 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004311 nodetest = NODE_TEST_NAME;
4312 }
4313 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4314 NEXT;
4315 prefix = name;
4316 if (CUR == '*') {
4317 NEXT;
4318 nodetest = NODE_TEST_ALL;
4319 } else
4320 name = xmlXPathParseNCName(ctxt);
4321 } else if (name == NULL)
4322 ERROR(XPATH_EXPR_ERROR);
4323 }
4324
4325search_nodes:
4326
4327#ifdef DEBUG_STEP
4328 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4329#endif
4330 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4331 prefix, name);
4332 if (ctxt->context->nodelist != NULL)
4333 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4334 ctxt->context->nodelist = newset;
4335 ctxt->context->node = NULL;
4336#ifdef DEBUG_STEP
4337 fprintf(xmlXPathDebug, "Basis : ");
4338 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4339#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004340 if (name != NULL) xmlFree(name);
4341 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004342}
4343
4344/**
4345 * xmlXPathEvalStep:
4346 * @ctxt: the XPath Parser context
4347 *
4348 * [4] Step ::= Basis Predicate*
4349 * | AbbreviatedStep
4350 * [12] AbbreviatedStep ::= '.'
4351 * | '..'
4352 *
4353 * Evaluate one step in a Location Path
4354 * A location step of . is short for self::node(). This is
4355 * particularly useful in conjunction with //. For example, the
4356 * location path .//para is short for
4357 * self::node()/descendant-or-self::node()/child::para
4358 * and so will select all para descendant elements of the context
4359 * node.
4360 * Similarly, a location step of .. is short for parent::node().
4361 * For example, ../title is short for parent::node()/child::title
4362 * and so will select the title children of the parent of the context
4363 * node.
4364 */
4365void
4366xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4367 xmlNodeSetPtr newset = NULL;
4368
Daniel Veillard00fdf371999-10-08 09:40:39 +00004369 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004370 if ((CUR == '.') && (NXT(1) == '.')) {
4371 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004372 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004373 if (ctxt->context->nodelist == NULL) {
4374 STRANGE
4375 xmlXPathRoot(ctxt);
4376 }
4377 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4378 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4379 if (ctxt->context->nodelist != NULL)
4380 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4381 ctxt->context->nodelist = newset;
4382 ctxt->context->node = NULL;
4383 } else if (CUR == '.') {
4384 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004385 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004386 } else {
4387 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004388 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004389 while (CUR == '[') {
4390 xmlXPathEvalPredicate(ctxt);
4391 }
4392 }
4393#ifdef DEBUG_STEP
4394 fprintf(xmlXPathDebug, "Step : ");
4395 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4396#endif
4397}
4398
4399/**
4400 * xmlXPathEvalRelativeLocationPath:
4401 * @ctxt: the XPath Parser context
4402 *
4403 * [3] RelativeLocationPath ::= Step
4404 * | RelativeLocationPath '/' Step
4405 * | AbbreviatedRelativeLocationPath
4406 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4407 *
4408 */
4409void
4410xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4411 xmlNodeSetPtr newset = NULL;
4412
Daniel Veillard00fdf371999-10-08 09:40:39 +00004413 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004414 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004415 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004416 while (CUR == '/') {
4417 if ((CUR == '/') && (NXT(1) == '/')) {
4418 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004419 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004420 if (ctxt->context->nodelist == NULL) {
4421 STRANGE
4422 xmlXPathRoot(ctxt);
4423 }
4424 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4425 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4426 if (ctxt->context->nodelist != NULL)
4427 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4428 ctxt->context->nodelist = newset;
4429 ctxt->context->node = NULL;
4430 xmlXPathEvalStep(ctxt);
4431 } else if (CUR == '/') {
4432 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004433 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004434 xmlXPathEvalStep(ctxt);
4435 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004436 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004437 }
4438}
4439
4440/**
4441 * xmlXPathEvalLocationPath:
4442 * @ctxt: the XPath Parser context
4443 *
4444 * [1] LocationPath ::= RelativeLocationPath
4445 * | AbsoluteLocationPath
4446 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4447 * | AbbreviatedAbsoluteLocationPath
4448 * [10] AbbreviatedAbsoluteLocationPath ::=
4449 * '//' RelativeLocationPath
4450 *
4451 * // is short for /descendant-or-self::node()/. For example,
4452 * //para is short for /descendant-or-self::node()/child::para and
4453 * so will select any para element in the document (even a para element
4454 * that is a document element will be selected by //para since the
4455 * document element node is a child of the root node); div//para is
4456 * short for div/descendant-or-self::node()/child::para and so will
4457 * select all para descendants of div children.
4458 */
4459void
4460xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4461 xmlNodeSetPtr newset = NULL;
4462
Daniel Veillard00fdf371999-10-08 09:40:39 +00004463 SKIP_BLANKS;
4464 if (CUR != '/') {
4465 xmlXPathEvalRelativeLocationPath(ctxt);
4466 } else {
4467 while (CUR == '/') {
4468 if ((CUR == '/') && (NXT(1) == '/')) {
4469 SKIP(2);
4470 SKIP_BLANKS;
4471 if (ctxt->context->nodelist == NULL)
4472 xmlXPathRoot(ctxt);
4473 newset = xmlXPathNodeCollectAndTest(ctxt,
4474 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4475 XML_ELEMENT_NODE, NULL, NULL);
4476 if (ctxt->context->nodelist != NULL)
4477 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4478 ctxt->context->nodelist = newset;
4479 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004480 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004481 } else if (CUR == '/') {
4482 NEXT;
4483 SKIP_BLANKS;
4484 xmlXPathRoot(ctxt);
4485 if (CUR != 0)
4486 xmlXPathEvalRelativeLocationPath(ctxt);
4487 } else {
4488 xmlXPathEvalRelativeLocationPath(ctxt);
4489 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004490 }
4491 }
4492}
4493
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004494/**
4495 * xmlXPathEval:
4496 * @str: the XPath expression
4497 * @ctxt: the XPath context
4498 *
4499 * Evaluate the XPath Location Path in the given context.
4500 *
4501 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4502 * the caller has to free the object.
4503 */
4504xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004505xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004506 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004507 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004508 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004509
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004510 xmlXPathInit();
4511
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004512 CHECK_CONTEXT
4513
4514 if (xmlXPathDebug == NULL)
4515 xmlXPathDebug = stderr;
4516 pctxt = xmlXPathNewParserContext(str, ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004517 if (str[0] == '/')
4518 xmlXPathRoot(pctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004519 xmlXPathEvalLocationPath(pctxt);
4520
Daniel Veillardb96e6431999-08-29 21:02:19 +00004521 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004522 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004523 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004524 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004525 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004526 stack++;
4527 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004528 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004529 if (stack != 0) {
4530 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4531 stack);
4532 }
4533 if (pctxt->error == XPATH_EXPRESSION_OK)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004534 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004535 else
4536 res = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004537 xmlXPathFreeParserContext(pctxt);
4538 return(res);
4539}
4540
4541/**
4542 * xmlXPathEvalExpression:
4543 * @str: the XPath expression
4544 * @ctxt: the XPath context
4545 *
4546 * Evaluate the XPath expression in the given context.
4547 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004548 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004549 * the caller has to free the object.
4550 */
4551xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004552xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004553 xmlXPathParserContextPtr pctxt;
4554 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004555 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004556
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004557 xmlXPathInit();
4558
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004559 CHECK_CONTEXT
4560
4561 if (xmlXPathDebug == NULL)
4562 xmlXPathDebug = stderr;
4563 pctxt = xmlXPathNewParserContext(str, ctxt);
4564 xmlXPathEvalExpr(pctxt);
4565
4566 res = valuePop(pctxt);
4567 do {
4568 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004569 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004570 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004571 stack++;
4572 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004573 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004574 if (stack != 0) {
4575 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4576 stack);
4577 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004578 xmlXPathFreeParserContext(pctxt);
4579 return(res);
4580}
4581