blob: 83b70875610713ac4598a49a7303e9fad6a46855 [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,
Daniel Veillard55b91f22000-10-05 16:30:11 +00004 * designed to be used by both XSLT and XPointer
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
Daniel Veillard1566d3a1999-07-15 14:24:29 +00008 * Public reference:
Daniel Veillard55b91f22000-10-05 16:30:11 +00009 * http://www.w3.org/TR/xpath
Daniel Veillard1566d3a1999-07-15 14:24:29 +000010 *
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
Daniel Veillardb71379b2000-10-09 12:30:39 +000022#include <libxml/xmlversion.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000023#ifdef LIBXML_XPATH_ENABLED
24
Daniel Veillard7f7d1111999-09-22 09:46:25 +000025#include <stdio.h>
26#include <string.h>
27
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000031#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000032#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000033#endif
34#ifdef HAVE_MATH_H
35#include <float.h>
36#endif
37#ifdef HAVE_IEEEFP_H
38#include <ieeefp.h>
39#endif
40#ifdef HAVE_NAN_H
41#include <nan.h>
42#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000043#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000044#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000045#endif
46
Daniel Veillard361d8452000-04-03 19:48:13 +000047#include <libxml/xmlmemory.h>
48#include <libxml/tree.h>
49#include <libxml/valid.h>
50#include <libxml/xpath.h>
51#include <libxml/parserInternals.h>
Daniel Veillardac260302000-10-04 13:33:43 +000052#ifdef LIBXML_XPTR_ENABLED
53#include <libxml/xpointer.h>
54#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +000055
Daniel Veillarddbfd6411999-12-28 16:35:14 +000056/* #define DEBUG */
57/* #define DEBUG_STEP */
58/* #define DEBUG_EXPR */
59
Daniel Veillard1566d3a1999-07-15 14:24:29 +000060/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000061 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000062 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000063 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000064double xmlXPathNAN = 0;
65double xmlXPathPINF = 1;
66double xmlXPathMINF = -1;
67
Daniel Veillardb05deb71999-08-10 19:04:08 +000068#ifndef isinf
69#ifndef HAVE_ISINF
70
71#if HAVE_FPCLASS
72
73int isinf(double d) {
74 fpclass_t type = fpclass(d);
75 switch (type) {
76 case FP_NINF:
77 return(-1);
78 case FP_PINF:
79 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000080 }
81 return(0);
82}
83
84#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
85
86#if HAVE_FP_CLASS_H
87#include <fp_class.h>
88#endif
89
90int isinf(double d) {
91#if HAVE_FP_CLASS
92 int fpclass = fp_class(d);
93#else
94 int fpclass = fp_class_d(d);
95#endif
96 if (fpclass == FP_POS_INF)
97 return(1);
98 if (fpclass == FP_NEG_INF)
99 return(-1);
100 return(0);
101}
102
103#elif defined(HAVE_CLASS)
104
105int isinf(double d) {
106 int fpclass = class(d);
107 if (fpclass == FP_PLUS_INF)
108 return(1);
109 if (fpclass == FP_MINUS_INF)
110 return(-1);
111 return(0);
112}
113#elif defined(finite) || defined(HAVE_FINITE)
114int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000115#elif defined(HUGE_VAL)
Daniel Veillardfc708e22000-04-08 13:17:27 +0000116int isinf(double x)
Daniel Veillard991e63d1999-08-15 23:32:28 +0000117{
118 if (x == HUGE_VAL)
119 return(1);
120 if (x == -HUGE_VAL)
121 return(-1);
122 return(0);
123}
124#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000125
126#endif /* ! HAVE_ISINF */
127#endif /* ! defined(isinf) */
128
129#ifndef isnan
130#ifndef HAVE_ISNAN
131
132#ifdef HAVE_ISNAND
133#define isnan(f) isnand(f)
134#endif /* HAVE_iSNAND */
135
136#endif /* ! HAVE_iSNAN */
137#endif /* ! defined(isnan) */
138
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000139/**
140 * xmlXPathInit:
141 *
142 * Initialize the XPath environment
143 */
144void
145xmlXPathInit(void) {
146 static int initialized = 0;
147
148 if (initialized) return;
149
150 xmlXPathNAN = 0;
151 xmlXPathNAN /= 0;
152
153 xmlXPathPINF = 1;
154 xmlXPathPINF /= 0;
155
156 xmlXPathMINF = -1;
157 xmlXPathMINF /= 0;
158
159 initialized = 1;
160}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000161
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000162FILE *xmlXPathDebug = NULL;
163
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000164double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000165void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000166
167/************************************************************************
168 * *
169 * Parser stacks related functions and macros *
170 * *
171 ************************************************************************/
172
Daniel Veillard7e99c632000-10-06 12:59:53 +0000173#define TODO \
174 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
175 __FILE__, __LINE__);
176
177#define STRANGE \
178 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
179 __FILE__, __LINE__);
180
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000181/*
182 * Generic function for accessing stacks in the Parser Context
183 */
184
185#define PUSH_AND_POP(type, name) \
186extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
187 if (ctxt->name##Nr >= ctxt->name##Max) { \
188 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000189 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000190 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
191 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000192 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000193 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000194 } \
195 } \
196 ctxt->name##Tab[ctxt->name##Nr] = value; \
197 ctxt->name = value; \
198 return(ctxt->name##Nr++); \
199} \
200extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
201 type ret; \
202 if (ctxt->name##Nr <= 0) return(0); \
203 ctxt->name##Nr--; \
204 if (ctxt->name##Nr > 0) \
205 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
206 else \
207 ctxt->name = NULL; \
208 ret = ctxt->name##Tab[ctxt->name##Nr]; \
209 ctxt->name##Tab[ctxt->name##Nr] = 0; \
210 return(ret); \
211} \
212
213PUSH_AND_POP(xmlXPathObjectPtr, value)
214
215/*
216 * Macros for accessing the content. Those should be used only by the parser,
217 * and not exported.
218 *
219 * Dirty macros, i.e. one need to make assumption on the context to use them
220 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000221 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000222 * CUR returns the current xmlChar value, i.e. a 8 bit value
223 * in ISO-Latin or UTF-8.
224 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000225 * only to compare to ASCII values otherwise it would break when
226 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000227 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000228 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000229 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000230 * strings within the parser.
231 * CURRENT Returns the current char value, with the full decoding of
232 * UTF-8 if we are using this mode. It returns an int.
233 * NEXT Skip to the next character, this does the proper decoding
234 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000235 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000236 */
237
238#define CUR (*ctxt->cur)
239#define SKIP(val) ctxt->cur += (val)
240#define NXT(val) ctxt->cur[(val)]
241#define CUR_PTR ctxt->cur
242
243#define SKIP_BLANKS \
244 while (IS_BLANK(*(ctxt->cur))) NEXT
245
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000246#define CURRENT (*ctxt->cur)
247#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000248
249/************************************************************************
250 * *
251 * Error handling routines *
252 * *
253 ************************************************************************/
254
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000255
256const char *xmlXPathErrorMessages[] = {
257 "Ok",
258 "Number encoding",
259 "Unfinished litteral",
260 "Start of litteral",
261 "Expected $ for variable reference",
262 "Undefined variable",
263 "Invalid predicate",
264 "Invalid expression",
265 "Missing closing curly brace",
266 "Unregistered function",
267 "Invalid operand",
268 "Invalid type",
269 "Invalid number of arguments",
Daniel Veillardf09e7e32000-10-01 15:53:30 +0000270 "Invalid context size",
271 "Invalid context position",
Daniel Veillardb71379b2000-10-09 12:30:39 +0000272 "Memory allocation error",
273 "Syntax error",
274 "Resource error",
275 "Sub resource error"
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000276};
277
278/**
279 * xmlXPathError:
280 * @ctxt: the XPath Parser context
281 * @file: the file name
282 * @line: the line number
283 * @no: the error number
284 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000285 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000286 *
287 * Returns the newly created object.
288 */
289void
290xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
291 int line, int no) {
292 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000293 const xmlChar *cur;
294 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000295
296 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
297 xmlXPathErrorMessages[no]);
298
299 cur = ctxt->cur;
300 base = ctxt->base;
301 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
302 cur--;
303 }
304 n = 0;
305 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
306 cur--;
307 if ((*cur == '\n') || (*cur == '\r')) cur++;
308 base = cur;
309 n = 0;
310 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
311 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
312 n++;
313 }
314 fprintf(xmlXPathDebug, "\n");
315 cur = ctxt->cur;
316 while ((*cur == '\n') || (*cur == '\r'))
317 cur--;
318 n = 0;
319 while ((cur != base) && (n++ < 80)) {
320 fprintf(xmlXPathDebug, " ");
321 base++;
322 }
323 fprintf(xmlXPathDebug,"^\n");
324}
325
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000326
327/************************************************************************
328 * *
329 * Routines to handle NodeSets *
330 * *
331 ************************************************************************/
332
333#define XML_NODESET_DEFAULT 10
334/**
335 * xmlXPathNodeSetCreate:
336 * @val: an initial xmlNodePtr, or NULL
337 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000338 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000339 *
340 * Returns the newly created object.
341 */
342xmlNodeSetPtr
343xmlXPathNodeSetCreate(xmlNodePtr val) {
344 xmlNodeSetPtr ret;
345
Daniel Veillard6454aec1999-09-02 22:04:43 +0000346 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000347 if (ret == NULL) {
348 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
349 return(NULL);
350 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000351 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000352 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000353 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000354 sizeof(xmlNodePtr));
355 if (ret->nodeTab == NULL) {
356 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
357 return(NULL);
358 }
359 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000360 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000361 ret->nodeMax = XML_NODESET_DEFAULT;
362 ret->nodeTab[ret->nodeNr++] = val;
363 }
364 return(ret);
365}
366
367/**
368 * xmlXPathNodeSetAdd:
369 * @cur: the initial node set
370 * @val: a new xmlNodePtr
371 *
372 * add a new xmlNodePtr ot an existing NodeSet
373 */
374void
375xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
376 int i;
377
378 if (val == NULL) return;
379
380 /*
381 * check against doublons
382 */
383 for (i = 0;i < cur->nodeNr;i++)
384 if (cur->nodeTab[i] == val) return;
385
386 /*
387 * grow the nodeTab if needed
388 */
389 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000390 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000391 sizeof(xmlNodePtr));
392 if (cur->nodeTab == NULL) {
393 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
394 return;
395 }
396 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000397 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000398 cur->nodeMax = XML_NODESET_DEFAULT;
399 } else if (cur->nodeNr == cur->nodeMax) {
400 xmlNodePtr *temp;
401
402 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000403 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000404 sizeof(xmlNodePtr));
405 if (temp == NULL) {
406 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
407 return;
408 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000409 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000410 }
411 cur->nodeTab[cur->nodeNr++] = val;
412}
413
414/**
415 * xmlXPathNodeSetMerge:
Daniel Veillard2d38f042000-10-11 10:54:10 +0000416 * @val1: the first NodeSet or NULL
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000417 * @val2: the second NodeSet
418 *
419 * Merges two nodesets, all nodes from @val2 are added to @val1
Daniel Veillard2d38f042000-10-11 10:54:10 +0000420 * if @val1 is NULL, a new set is created and copied from @val2
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000421 *
422 * Returns val1 once extended or NULL in case of error.
423 */
424xmlNodeSetPtr
425xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
426 int i;
427
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000428 if (val2 == NULL) return(val1);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000429 if (val1 == NULL) {
430 val1 = xmlXPathNodeSetCreate(NULL);
431 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000432
433 /*
434 * !!!!! this can be optimized a lot, knowing that both
435 * val1 and val2 already have unicity of their values.
436 */
437
438 for (i = 0;i < val2->nodeNr;i++)
439 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
440
441 return(val1);
442}
443
444/**
445 * xmlXPathNodeSetDel:
446 * @cur: the initial node set
447 * @val: an xmlNodePtr
448 *
449 * Removes an xmlNodePtr from an existing NodeSet
450 */
451void
452xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
453 int i;
454
455 if (cur == NULL) return;
456 if (val == NULL) return;
457
458 /*
459 * check against doublons
460 */
461 for (i = 0;i < cur->nodeNr;i++)
462 if (cur->nodeTab[i] == val) break;
463
464 if (i >= cur->nodeNr) {
465#ifdef DEBUG
466 fprintf(xmlXPathDebug,
467 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
468 val->name);
469#endif
470 return;
471 }
472 cur->nodeNr--;
473 for (;i < cur->nodeNr;i++)
474 cur->nodeTab[i] = cur->nodeTab[i + 1];
475 cur->nodeTab[cur->nodeNr] = NULL;
476}
477
478/**
479 * xmlXPathNodeSetRemove:
480 * @cur: the initial node set
481 * @val: the index to remove
482 *
483 * Removes an entry from an existing NodeSet list.
484 */
485void
486xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
487 if (cur == NULL) return;
488 if (val >= cur->nodeNr) return;
489 cur->nodeNr--;
490 for (;val < cur->nodeNr;val++)
491 cur->nodeTab[val] = cur->nodeTab[val + 1];
492 cur->nodeTab[cur->nodeNr] = NULL;
493}
494
495/**
496 * xmlXPathFreeNodeSet:
497 * @obj: the xmlNodeSetPtr to free
498 *
499 * Free the NodeSet compound (not the actual nodes !).
500 */
501void
502xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
503 if (obj == NULL) return;
504 if (obj->nodeTab != NULL) {
505#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000506 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000507#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000508 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000509 }
510#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000511 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000512#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000513 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000514}
515
Daniel Veillardb96e6431999-08-29 21:02:19 +0000516#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000517/**
518 * xmlXPathDebugNodeSet:
519 * @output: a FILE * for the output
520 * @obj: the xmlNodeSetPtr to free
521 *
522 * Quick display of a NodeSet
523 */
524void
525xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
526 int i;
527
528 if (output == NULL) output = xmlXPathDebug;
529 if (obj == NULL) {
530 fprintf(output, "NodeSet == NULL !\n");
531 return;
532 }
533 if (obj->nodeNr == 0) {
534 fprintf(output, "NodeSet is empty\n");
535 return;
536 }
537 if (obj->nodeTab == NULL) {
538 fprintf(output, " nodeTab == NULL !\n");
539 return;
540 }
541 for (i = 0; i < obj->nodeNr; i++) {
542 if (obj->nodeTab[i] == NULL) {
543 fprintf(output, " NULL !\n");
544 return;
545 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000546 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
547 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000548 fprintf(output, " /");
549 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000550 fprintf(output, " noname!");
551 else fprintf(output, " %s", obj->nodeTab[i]->name);
552 }
553 fprintf(output, "\n");
554}
555#endif
556
Daniel Veillard7e99c632000-10-06 12:59:53 +0000557/**
558 * xmlXPathNewNodeSet:
559 * @val: the NodePtr value
560 *
561 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
562 * it with the single Node @val
563 *
564 * Returns the newly created object.
565 */
566xmlXPathObjectPtr
567xmlXPathNewNodeSet(xmlNodePtr val) {
568 xmlXPathObjectPtr ret;
569
570 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
571 if (ret == NULL) {
572 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
573 return(NULL);
574 }
575 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
576 ret->type = XPATH_NODESET;
577 ret->nodesetval = xmlXPathNodeSetCreate(val);
578 return(ret);
579}
580
581/**
582 * xmlXPathNewNodeSetList:
583 * @val: an existing NodeSet
584 *
585 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
586 * it with the Nodeset @val
587 *
588 * Returns the newly created object.
589 */
590xmlXPathObjectPtr
591xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
592 xmlXPathObjectPtr ret;
593 int i;
594
595 if (val == NULL)
596 ret = NULL;
597 else if (val->nodeTab == NULL)
598 ret = xmlXPathNewNodeSet(NULL);
599 else
600 {
601 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
602 for (i = 1; i < val->nodeNr; ++i)
603 xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
604 }
605
606 return(ret);
607}
608
609/**
610 * xmlXPathWrapNodeSet:
611 * @val: the NodePtr value
612 *
613 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
614 *
615 * Returns the newly created object.
616 */
617xmlXPathObjectPtr
618xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
619 xmlXPathObjectPtr ret;
620
621 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
622 if (ret == NULL) {
623 fprintf(xmlXPathDebug, "xmlXPathWrapNodeSet: out of memory\n");
624 return(NULL);
625 }
626 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
627 ret->type = XPATH_NODESET;
628 ret->nodesetval = val;
629 return(ret);
630}
631
632/**
633 * xmlXPathFreeNodeSetList:
634 * @obj: an existing NodeSetList object
635 *
636 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
637 * the list contrary to xmlXPathFreeObject().
638 */
639void
640xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
641 if (obj == NULL) return;
642#ifdef DEBUG
643 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
644#endif
645 xmlFree(obj);
646}
647
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000648/************************************************************************
649 * *
Daniel Veillard2d38f042000-10-11 10:54:10 +0000650 * Routines to handle extra functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000651 * *
652 ************************************************************************/
653
654/**
Daniel Veillard2d38f042000-10-11 10:54:10 +0000655 * xmlXPathRegisterFunc:
656 * @ctxt: the XPath context
657 * @name: the function name
658 * @f: the function implementation or NULL
659 *
660 * Register a new function. If @f is NULL it unregisters the function
661 *
662 * Returns 0 in case of success, -1 in case of error
663 */
664int
665xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
666 xmlXPathFunction f) {
667 int i;
668
669 if (ctxt == NULL)
670 return(-1);
671 if (name == NULL)
672 return(-1);
673
674 for (i = 0;i < ctxt->nb_funcs;i++) {
675 if (xmlStrEqual(ctxt->funcs[i]->name, name)) {
676 /*
677 * It's just an update or a removal
678 */
679 ctxt->funcs[i]->func = f;
680 return(0);
681 }
682 }
683 if (ctxt->max_funcs <= 0) {
684 ctxt->max_funcs = 10;
685 ctxt->nb_funcs = 0;
686 ctxt->funcs = (xmlXPathFuncPtr *) xmlMalloc(ctxt->max_funcs *
687 sizeof(xmlXPathFuncPtr));
688 } else if (ctxt->max_funcs <= ctxt->nb_funcs) {
689 ctxt->max_funcs *= 2;
690 ctxt->funcs = (xmlXPathFuncPtr *) xmlRealloc(ctxt->funcs,
691 ctxt->max_funcs * sizeof(xmlXPathFuncPtr));
692 }
693 if (ctxt->funcs == NULL) {
694 fprintf(xmlXPathDebug, "xmlXPathRegisterFunc: out of memory\n");
695 return(-1);
696 }
697 ctxt->funcs[i]->name = xmlStrdup(name);
698 ctxt->funcs[i]->func = f;
699 return(0);
700}
701
702/**
703 * xmlXPathFunctionLookup:
704 * @ctxt: the XPath context
705 * @name: the function name
706 *
707 * Search in the Function array of the context for the given
708 * function.
709 *
710 * Returns the xmlXPathFunction or NULL if not found
711 */
712xmlXPathFunction
713xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
714 int i;
715
716 if (ctxt == NULL)
717 return(NULL);
718 if (name == NULL)
719 return(NULL);
720
721 for (i = 0;i < ctxt->nb_funcs;i++) {
722 if (xmlStrEqual(ctxt->funcs[i]->name, name)) {
723 return(ctxt->funcs[i]->func);
724 }
725 }
726 return(NULL);
727}
728
729/**
730 * xmlXPathRegisteredFuncsCleanup:
731 * @ctxt: the XPath context
732 *
733 * Cleanup the XPath context data associated to registered functions
734 */
735void
736xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
737 int i;
738
739 if (ctxt == NULL)
740 return;
741
742 for (i = 0;i < ctxt->nb_funcs;i++) {
743 xmlFree((xmlChar *) ctxt->funcs[i]->name);
744 }
745 ctxt->nb_funcs = -1;
746 ctxt->max_funcs = -1;
747 if (ctxt->funcs != NULL)
748 xmlFree(ctxt->funcs);
749 ctxt->funcs = NULL;
750}
751
752/************************************************************************
753 * *
754 * Routines to handle Variable *
755 * *
756 ************************************************************************/
757
758/**
759 * xmlXPathRegisterVariable:
760 * @ctxt: the XPath context
761 * @name: the variable name
762 * @value: the variable value or NULL
763 *
764 * Register a new variable value. If @value is NULL it unregisters
765 * the variable
766 *
767 * Returns 0 in case of success, -1 in case of error
768 */
769int
770xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
771 xmlXPathObjectPtr value) {
772 int i;
773
774 if (ctxt == NULL)
775 return(-1);
776 if (name == NULL)
777 return(-1);
778
779 for (i = 0;i < ctxt->nb_variables;i++) {
780 if (xmlStrEqual(ctxt->variables[i]->name, name)) {
781 /*
782 * It's just an update or a removal
783 */
784 if (ctxt->variables[i]->value != NULL) {
785 xmlXPathFreeObject(ctxt->variables[i]->value);
786 }
787 ctxt->variables[i]->value = xmlXPathObjectCopy(value);
788 return(0);
789 }
790 }
791 if (ctxt->max_variables <= 0) {
792 ctxt->max_variables = 10;
793 ctxt->nb_variables = 0;
794 ctxt->variables = (xmlXPathVariablePtr *)
795 xmlMalloc(ctxt->max_variables * sizeof(xmlXPathVariablePtr));
796 } else if (ctxt->max_variables <= ctxt->nb_variables) {
797 ctxt->max_variables *= 2;
798 ctxt->variables = (xmlXPathVariablePtr *)
799 xmlRealloc(ctxt->variables,
800 ctxt->max_variables * sizeof(xmlXPathVariablePtr));
801 }
802 if (ctxt->variables == NULL) {
803 fprintf(xmlXPathDebug, "xmlXPathRegisterVariable: out of memory\n");
804 return(-1);
805 }
806 ctxt->variables[i]->name = xmlStrdup(name);
807 ctxt->variables[i]->value = xmlXPathObjectCopy(value);
808 return(0);
809}
810
811/**
812 * xmlXPathVariableLookup:
813 * @ctxt: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000814 * @name: the variable name
815 *
816 * Search in the Variable array of the context for the given
817 * variable value.
818 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000819 * Returns the value or NULL if not found
820 */
821xmlXPathObjectPtr
Daniel Veillard2d38f042000-10-11 10:54:10 +0000822xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
823 int i;
824
825 if (ctxt == NULL)
826 return(NULL);
827 if (name == NULL)
828 return(NULL);
829
830 for (i = 0;i < ctxt->nb_variables;i++) {
831 if (xmlStrEqual(ctxt->variables[i]->name, name)) {
832 return(xmlXPathObjectCopy(ctxt->variables[i]->value));
833 }
834 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000835 return(NULL);
836}
837
Daniel Veillard2d38f042000-10-11 10:54:10 +0000838/**
839 * xmlXPathRegisteredVariablesCleanup:
840 * @ctxt: the XPath context
841 *
842 * Cleanup the XPath context data associated to registered variables
843 */
844void
845xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
846 int i;
847
848 if (ctxt == NULL)
849 return;
850
851 for (i = 0;i < ctxt->nb_variables;i++) {
852 xmlFree((xmlChar *) ctxt->variables[i]->name);
853 xmlXPathFreeObject(ctxt->variables[i]->value);
854 }
855 ctxt->nb_variables = -1;
856 ctxt->max_variables = -1;
857 if (ctxt->variables != NULL)
858 xmlFree(ctxt->variables);
859 ctxt->variables = NULL;
860}
861
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000862/************************************************************************
863 * *
864 * Routines to handle Values *
865 * *
866 ************************************************************************/
867
868/* Allocations are terrible, one need to optimize all this !!! */
869
870/**
871 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000872 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000873 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000874 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000875 *
876 * Returns the newly created object.
877 */
878xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000879xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000880 xmlXPathObjectPtr ret;
881
Daniel Veillard6454aec1999-09-02 22:04:43 +0000882 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000883 if (ret == NULL) {
884 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
885 return(NULL);
886 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000887 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000888 ret->type = XPATH_NUMBER;
889 ret->floatval = val;
890 return(ret);
891}
892
893/**
894 * xmlXPathNewBoolean:
895 * @val: the boolean value
896 *
897 * Create a new xmlXPathObjectPtr of type boolean and of value @val
898 *
899 * Returns the newly created object.
900 */
901xmlXPathObjectPtr
902xmlXPathNewBoolean(int val) {
903 xmlXPathObjectPtr ret;
904
Daniel Veillard6454aec1999-09-02 22:04:43 +0000905 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000906 if (ret == NULL) {
Daniel Veillard740abf52000-10-02 23:04:54 +0000907 fprintf(xmlXPathDebug, "xmlXPathNewBoolean: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000908 return(NULL);
909 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000910 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000911 ret->type = XPATH_BOOLEAN;
912 ret->boolval = (val != 0);
913 return(ret);
914}
915
916/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000917 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000918 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000919 *
920 * Create a new xmlXPathObjectPtr of type string and of value @val
921 *
922 * Returns the newly created object.
923 */
924xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000925xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000926 xmlXPathObjectPtr ret;
927
Daniel Veillard6454aec1999-09-02 22:04:43 +0000928 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000929 if (ret == NULL) {
Daniel Veillard740abf52000-10-02 23:04:54 +0000930 fprintf(xmlXPathDebug, "xmlXPathNewString: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000931 return(NULL);
932 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000933 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000934 ret->type = XPATH_STRING;
935 ret->stringval = xmlStrdup(val);
936 return(ret);
937}
938
939/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000940 * xmlXPathNewCString:
941 * @val: the char * value
942 *
943 * Create a new xmlXPathObjectPtr of type string and of value @val
944 *
945 * Returns the newly created object.
946 */
947xmlXPathObjectPtr
948xmlXPathNewCString(const char *val) {
949 xmlXPathObjectPtr ret;
950
Daniel Veillard6454aec1999-09-02 22:04:43 +0000951 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000952 if (ret == NULL) {
Daniel Veillard740abf52000-10-02 23:04:54 +0000953 fprintf(xmlXPathDebug, "xmlXPathNewCString: out of memory\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +0000954 return(NULL);
955 }
956 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
957 ret->type = XPATH_STRING;
958 ret->stringval = xmlStrdup(BAD_CAST val);
959 return(ret);
960}
961
962/**
Daniel Veillard2d38f042000-10-11 10:54:10 +0000963 * xmlXPathObjectCopy:
964 * @val: the original object
965 *
966 * allocate a new copy of a given object
967 *
968 * Returns the newly created object.
969 */
970xmlXPathObjectPtr
971xmlXPathObjectCopy(xmlXPathObjectPtr val) {
972 xmlXPathObjectPtr ret;
973
974 if (val == NULL)
975 return(NULL);
976
977 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
978 if (ret == NULL) {
979 fprintf(xmlXPathDebug, "xmlXPathObjectCopy: out of memory\n");
980 return(NULL);
981 }
982 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
983 switch (val->type) {
984 case XPATH_BOOLEAN:
985 case XPATH_NUMBER:
986 case XPATH_STRING:
987 case XPATH_POINT:
988 case XPATH_RANGE:
989 break;
990 case XPATH_NODESET:
991 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
992 break;
993 case XPATH_LOCATIONSET:
994#ifdef LIBXML_XPTR_ENABLED
995 {
996 xmlLocationSetPtr loc = val->user;
997 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
998 break;
999 }
1000#endif
1001 case XPATH_UNDEFINED:
1002 case XPATH_USERS:
1003 fprintf(xmlXPathDebug, "xmlXPathObjectCopy: unsupported type %d\n",
1004 val->type);
1005 }
1006 return(ret);
1007}
1008
1009/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001010 * xmlXPathFreeObject:
1011 * @obj: the object to free
1012 *
1013 * Free up an xmlXPathObjectPtr object.
1014 */
1015void
1016xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1017 if (obj == NULL) return;
Daniel Veillardac260302000-10-04 13:33:43 +00001018 if (obj->type == XPATH_NODESET) {
1019 if (obj->nodesetval != NULL)
1020 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001021#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard7e99c632000-10-06 12:59:53 +00001022 } else if (obj->type == XPATH_LOCATIONSET) {
1023 if (obj->user != NULL)
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00001024 xmlXPtrFreeLocationSet(obj->user);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001025#endif
Daniel Veillardac260302000-10-04 13:33:43 +00001026 } else if (obj->type == XPATH_STRING) {
1027 if (obj->stringval != NULL)
1028 xmlFree(obj->stringval);
1029 }
1030
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001031#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001032 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001033#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001034 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001035}
1036
1037/************************************************************************
1038 * *
1039 * Routines to handle XPath contexts *
1040 * *
1041 ************************************************************************/
1042
1043/**
1044 * xmlXPathNewContext:
1045 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001046 *
1047 * Create a new xmlXPathContext
1048 *
1049 * Returns the xmlXPathContext just allocated.
1050 */
1051xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001052xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001053 xmlXPathContextPtr ret;
1054
Daniel Veillard6454aec1999-09-02 22:04:43 +00001055 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001056 if (ret == NULL) {
1057 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
1058 return(NULL);
1059 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001060 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001061 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001062 ret->node = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001063
1064 ret->nb_variables = 0;
1065 ret->max_variables = 0;
1066 ret->variables = NULL;
1067
1068 ret->nb_types = 0;
1069 ret->max_types = 0;
1070 ret->types = NULL;
1071
1072 ret->nb_funcs = 0;
1073 ret->max_funcs = 0;
1074 ret->funcs = NULL;
1075
1076 ret->nb_axis = 0;
1077 ret->max_axis = 0;
1078 ret->axis = NULL;
1079
Daniel Veillardb96e6431999-08-29 21:02:19 +00001080 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001081 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001082 ret->nsNr = 0;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001083
1084 ret->contextSize = -1;
1085 ret->proximityPosition = -1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001086 return(ret);
1087}
1088
1089/**
1090 * xmlXPathFreeContext:
1091 * @ctxt: the context to free
1092 *
1093 * Free up an xmlXPathContext
1094 */
1095void
1096xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001097 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001098 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001099
Daniel Veillard2d38f042000-10-11 10:54:10 +00001100 xmlXPathRegisteredFuncsCleanup(ctxt);
1101 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001102#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001103 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001104#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001105 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001106}
1107
1108/************************************************************************
1109 * *
1110 * Routines to handle XPath parser contexts *
1111 * *
1112 ************************************************************************/
1113
Daniel Veillard740abf52000-10-02 23:04:54 +00001114#define CHECK_CTXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001115 if (ctxt == NULL) { \
1116 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
1117 __FILE__, __LINE__); \
1118 } \
1119
1120
Daniel Veillard740abf52000-10-02 23:04:54 +00001121#define CHECK_CONTEXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001122 if (ctxt == NULL) { \
1123 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
1124 __FILE__, __LINE__); \
1125 } \
1126 if (ctxt->doc == NULL) { \
1127 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
1128 __FILE__, __LINE__); \
1129 } \
Daniel Veillardcf461992000-03-14 18:30:20 +00001130 if (ctxt->doc->children == NULL) { \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001131 fprintf(xmlXPathDebug, \
1132 "%s:%d Internal error: document without root\n", \
1133 __FILE__, __LINE__); \
1134 } \
1135
1136
1137/**
1138 * xmlXPathNewParserContext:
1139 * @str: the XPath expression
1140 * @ctxt: the XPath context
1141 *
1142 * Create a new xmlXPathParserContext
1143 *
1144 * Returns the xmlXPathParserContext just allocated.
1145 */
1146xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001147xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001148 xmlXPathParserContextPtr ret;
1149
Daniel Veillard6454aec1999-09-02 22:04:43 +00001150 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001151 if (ret == NULL) {
1152 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
1153 return(NULL);
1154 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001155 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001156 ret->cur = ret->base = str;
1157 ret->context = ctxt;
1158
1159 /* Allocate the value stack */
1160 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001161 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001162 ret->valueNr = 0;
1163 ret->valueMax = 10;
1164 ret->value = NULL;
1165 return(ret);
1166}
1167
1168/**
1169 * xmlXPathFreeParserContext:
1170 * @ctxt: the context to free
1171 *
1172 * Free up an xmlXPathParserContext
1173 */
1174void
1175xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1176 if (ctxt->valueTab != NULL) {
1177#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001178 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001179#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001180 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001181 }
1182#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001183 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001184#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001185 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001186}
1187
1188/************************************************************************
1189 * *
1190 * The implicit core function library *
1191 * *
1192 ************************************************************************/
1193
1194/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001195 * Auto-pop and cast to a number
1196 */
1197void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1198
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001199
1200#define POP_FLOAT \
1201 arg = valuePop(ctxt); \
1202 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001203 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001204 } \
1205 if (arg->type != XPATH_NUMBER) { \
1206 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001207 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001208 arg = valuePop(ctxt); \
1209 }
1210
1211/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001212 * xmlXPathEqualNodeSetString
1213 * @arg: the nodeset object argument
1214 * @str: the string to compare to.
1215 *
1216 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1217 * If one object to be compared is a node-set and the other is a string,
1218 * then the comparison will be true if and only if there is a node in
1219 * the node-set such that the result of performing the comparison on the
1220 * string-value of the node and the other string is true.
1221 *
1222 * Returns 0 or 1 depending on the results of the test.
1223 */
1224int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001225xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001226 int i;
1227 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001228 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001229
1230 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
1231 return(0);
1232 ns = arg->nodesetval;
1233 for (i = 0;i < ns->nodeNr;i++) {
1234 str2 = xmlNodeGetContent(ns->nodeTab[i]);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001235 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001236 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001237 return(1);
1238 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001239 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001240 }
1241 return(0);
1242}
1243
1244/**
1245 * xmlXPathEqualNodeSetFloat
1246 * @arg: the nodeset object argument
1247 * @f: the float to compare to
1248 *
1249 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1250 * If one object to be compared is a node-set and the other is a number,
1251 * then the comparison will be true if and only if there is a node in
1252 * the node-set such that the result of performing the comparison on the
1253 * number to be compared and on the result of converting the string-value
1254 * of that node to a number using the number function is true.
1255 *
1256 * Returns 0 or 1 depending on the results of the test.
1257 */
1258int
1259xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001260 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001261
1262 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1263 return(0);
1264
1265 if (isnan(f))
1266 sprintf(buf, "NaN");
1267 else if (isinf(f) > 0)
1268 sprintf(buf, "+Infinity");
1269 else if (isinf(f) < 0)
1270 sprintf(buf, "-Infinity");
1271 else
1272 sprintf(buf, "%0g", f);
1273
Daniel Veillardb96e6431999-08-29 21:02:19 +00001274 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001275}
1276
1277
1278/**
1279 * xmlXPathEqualNodeSets
1280 * @arg1: first nodeset object argument
1281 * @arg2: second nodeset object argument
1282 *
1283 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1284 * If both objects to be compared are node-sets, then the comparison
1285 * will be true if and only if there is a node in the first node-set and
1286 * a node in the second node-set such that the result of performing the
1287 * comparison on the string-values of the two nodes is true.
1288 *
1289 * (needless to say, this is a costly operation)
1290 *
1291 * Returns 0 or 1 depending on the results of the test.
1292 */
1293int
1294xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1295 int i;
1296 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001297 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001298
1299 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1300 return(0);
1301 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1302 return(0);
1303
1304 ns = arg1->nodesetval;
1305 for (i = 0;i < ns->nodeNr;i++) {
1306 str = xmlNodeGetContent(ns->nodeTab[i]);
1307 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001308 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001309 return(1);
1310 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001311 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001312 }
1313 return(0);
1314}
1315
1316/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001317 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001318 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001319 *
1320 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1321 *
1322 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001323 */
1324int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001325xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1326 xmlXPathObjectPtr arg1, arg2;
1327 int ret = 0;
1328
1329 arg1 = valuePop(ctxt);
1330 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001331 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001332
1333 arg2 = valuePop(ctxt);
1334 if (arg2 == NULL) {
1335 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001336 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001337 }
1338
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001339 if (arg1 == arg2) {
1340#ifdef DEBUG_EXPR
1341 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1342#endif
1343 return(1);
1344 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001345
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001346 switch (arg1->type) {
1347 case XPATH_UNDEFINED:
1348#ifdef DEBUG_EXPR
1349 fprintf(xmlXPathDebug, "Equal: undefined\n");
1350#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001351 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001352 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001353 switch (arg2->type) {
1354 case XPATH_UNDEFINED:
1355#ifdef DEBUG_EXPR
1356 fprintf(xmlXPathDebug, "Equal: undefined\n");
1357#endif
1358 break;
1359 case XPATH_NODESET:
1360 ret = xmlXPathEqualNodeSets(arg1, arg2);
1361 break;
1362 case XPATH_BOOLEAN:
1363 if ((arg1->nodesetval == NULL) ||
1364 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1365 else
1366 ret = 1;
1367 ret = (ret == arg2->boolval);
1368 break;
1369 case XPATH_NUMBER:
1370 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1371 break;
1372 case XPATH_STRING:
1373 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1374 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001375 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001376 case XPATH_POINT:
1377 case XPATH_RANGE:
1378 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001379 TODO
1380 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001381 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001382 break;
1383 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001384 switch (arg2->type) {
1385 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001386#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001387 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001388#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001389 break;
1390 case XPATH_NODESET:
1391 if ((arg2->nodesetval == NULL) ||
1392 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1393 else
1394 ret = 1;
1395 break;
1396 case XPATH_BOOLEAN:
1397#ifdef DEBUG_EXPR
1398 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1399 arg1->boolval, arg2->boolval);
1400#endif
1401 ret = (arg1->boolval == arg2->boolval);
1402 break;
1403 case XPATH_NUMBER:
1404 if (arg2->floatval) ret = 1;
1405 else ret = 0;
1406 ret = (arg1->boolval == ret);
1407 break;
1408 case XPATH_STRING:
1409 if ((arg2->stringval == NULL) ||
1410 (arg2->stringval[0] == 0)) ret = 0;
1411 else
1412 ret = 1;
1413 ret = (arg1->boolval == ret);
1414 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001415 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001416 case XPATH_POINT:
1417 case XPATH_RANGE:
1418 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001419 TODO
1420 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001421 }
1422 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001423 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001424 switch (arg2->type) {
1425 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001426#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001427 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001428#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001429 break;
1430 case XPATH_NODESET:
1431 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1432 break;
1433 case XPATH_BOOLEAN:
1434 if (arg1->floatval) ret = 1;
1435 else ret = 0;
1436 ret = (arg2->boolval == ret);
1437 break;
1438 case XPATH_STRING:
1439 valuePush(ctxt, arg2);
1440 xmlXPathNumberFunction(ctxt, 1);
1441 arg2 = valuePop(ctxt);
1442 /* no break on purpose */
1443 case XPATH_NUMBER:
1444 ret = (arg1->floatval == arg2->floatval);
1445 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001446 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001447 case XPATH_POINT:
1448 case XPATH_RANGE:
1449 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001450 TODO
1451 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001452 }
1453 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001454 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001455 switch (arg2->type) {
1456 case XPATH_UNDEFINED:
1457#ifdef DEBUG_EXPR
1458 fprintf(xmlXPathDebug, "Equal: undefined\n");
1459#endif
1460 break;
1461 case XPATH_NODESET:
1462 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1463 break;
1464 case XPATH_BOOLEAN:
1465 if ((arg1->stringval == NULL) ||
1466 (arg1->stringval[0] == 0)) ret = 0;
1467 else
1468 ret = 1;
1469 ret = (arg2->boolval == ret);
1470 break;
1471 case XPATH_STRING:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001472 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001473 break;
1474 case XPATH_NUMBER:
1475 valuePush(ctxt, arg1);
1476 xmlXPathNumberFunction(ctxt, 1);
1477 arg1 = valuePop(ctxt);
1478 ret = (arg1->floatval == arg2->floatval);
1479 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001480 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001481 case XPATH_POINT:
1482 case XPATH_RANGE:
1483 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001484 TODO
1485 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001486 }
1487 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001488 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001489 case XPATH_POINT:
1490 case XPATH_RANGE:
1491 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001492 TODO
1493 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001494 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001495 xmlXPathFreeObject(arg1);
1496 xmlXPathFreeObject(arg2);
1497 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001498}
1499
1500/**
1501 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001502 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001503 * @inf: less than (1) or greater than (2)
1504 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001505 *
1506 * Implement the compare operation on XPath objects:
1507 * @arg1 < @arg2 (1, 1, ...
1508 * @arg1 <= @arg2 (1, 0, ...
1509 * @arg1 > @arg2 (0, 1, ...
1510 * @arg1 >= @arg2 (0, 0, ...
1511 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001512 * When neither object to be compared is a node-set and the operator is
1513 * <=, <, >=, >, then the objects are compared by converted both objects
1514 * to numbers and comparing the numbers according to IEEE 754. The <
1515 * comparison will be true if and only if the first number is less than the
1516 * second number. The <= comparison will be true if and only if the first
1517 * number is less than or equal to the second number. The > comparison
1518 * will be true if and only if the first number is greater than the second
1519 * number. The >= comparison will be true if and only if the first number
1520 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001521 */
1522int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001523xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1524 int ret = 0;
1525 xmlXPathObjectPtr arg1, arg2;
1526
1527 arg2 = valuePop(ctxt);
1528 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1529 if (arg2 != NULL)
1530 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001531 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001532 }
1533
1534 arg1 = valuePop(ctxt);
1535 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1536 if (arg1 != NULL)
1537 xmlXPathFreeObject(arg1);
1538 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001539 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001540 }
1541
1542 if (arg1->type != XPATH_NUMBER) {
1543 valuePush(ctxt, arg1);
1544 xmlXPathNumberFunction(ctxt, 1);
1545 arg1 = valuePop(ctxt);
1546 }
1547 if (arg1->type != XPATH_NUMBER) {
1548 xmlXPathFreeObject(arg1);
1549 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001550 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001551 }
1552 if (arg2->type != XPATH_NUMBER) {
1553 valuePush(ctxt, arg2);
1554 xmlXPathNumberFunction(ctxt, 1);
1555 arg2 = valuePop(ctxt);
1556 }
1557 if (arg2->type != XPATH_NUMBER) {
1558 xmlXPathFreeObject(arg1);
1559 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001560 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001561 }
1562 /*
1563 * Add tests for infinity and nan
1564 * => feedback on 3.4 for Inf and NaN
1565 */
1566 if (inf && strict)
1567 ret = (arg1->floatval < arg2->floatval);
1568 else if (inf && !strict)
1569 ret = (arg1->floatval <= arg2->floatval);
1570 else if (!inf && strict)
1571 ret = (arg1->floatval > arg2->floatval);
1572 else if (!inf && !strict)
1573 ret = (arg1->floatval >= arg2->floatval);
1574 xmlXPathFreeObject(arg1);
1575 xmlXPathFreeObject(arg2);
1576 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001577}
1578
1579/**
1580 * xmlXPathValueFlipSign:
1581 * @ctxt: the XPath Parser context
1582 *
1583 * Implement the unary - operation on an XPath object
1584 * The numeric operators convert their operands to numbers as if
1585 * by calling the number function.
1586 */
1587void
1588xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1589 xmlXPathObjectPtr arg;
1590
1591 POP_FLOAT
1592 arg->floatval = -arg->floatval;
1593 valuePush(ctxt, arg);
1594}
1595
1596/**
1597 * xmlXPathAddValues:
1598 * @ctxt: the XPath Parser context
1599 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001600 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001601 * The numeric operators convert their operands to numbers as if
1602 * by calling the number function.
1603 */
1604void
1605xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1606 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001607 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001608
1609 POP_FLOAT
1610 val = arg->floatval;
1611 xmlXPathFreeObject(arg);
1612
1613 POP_FLOAT
1614 arg->floatval += val;
1615 valuePush(ctxt, arg);
1616}
1617
1618/**
1619 * xmlXPathSubValues:
1620 * @ctxt: the XPath Parser context
1621 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001622 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001623 * The numeric operators convert their operands to numbers as if
1624 * by calling the number function.
1625 */
1626void
1627xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1628 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001629 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001630
1631 POP_FLOAT
1632 val = arg->floatval;
1633 xmlXPathFreeObject(arg);
1634
1635 POP_FLOAT
1636 arg->floatval -= val;
1637 valuePush(ctxt, arg);
1638}
1639
1640/**
1641 * xmlXPathMultValues:
1642 * @ctxt: the XPath Parser context
1643 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001644 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001645 * The numeric operators convert their operands to numbers as if
1646 * by calling the number function.
1647 */
1648void
1649xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1650 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001651 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001652
1653 POP_FLOAT
1654 val = arg->floatval;
1655 xmlXPathFreeObject(arg);
1656
1657 POP_FLOAT
1658 arg->floatval *= val;
1659 valuePush(ctxt, arg);
1660}
1661
1662/**
1663 * xmlXPathDivValues:
1664 * @ctxt: the XPath Parser context
1665 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001666 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001667 * The numeric operators convert their operands to numbers as if
1668 * by calling the number function.
1669 */
1670void
1671xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1672 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001673 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001674
1675 POP_FLOAT
1676 val = arg->floatval;
1677 xmlXPathFreeObject(arg);
1678
1679 POP_FLOAT
1680 arg->floatval /= val;
1681 valuePush(ctxt, arg);
1682}
1683
1684/**
1685 * xmlXPathModValues:
1686 * @ctxt: the XPath Parser context
1687 *
1688 * Implement the div operation on XPath objects: @arg1 / @arg2
1689 * The numeric operators convert their operands to numbers as if
1690 * by calling the number function.
1691 */
1692void
1693xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1694 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001695 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001696
1697 POP_FLOAT
1698 val = arg->floatval;
1699 xmlXPathFreeObject(arg);
1700
1701 POP_FLOAT
1702 arg->floatval /= val;
1703 valuePush(ctxt, arg);
1704}
1705
1706/************************************************************************
1707 * *
1708 * The traversal functions *
1709 * *
1710 ************************************************************************/
1711
Daniel Veillard740abf52000-10-02 23:04:54 +00001712typedef enum {
1713 AXIS_ANCESTOR = 1,
1714 AXIS_ANCESTOR_OR_SELF,
1715 AXIS_ATTRIBUTE,
1716 AXIS_CHILD,
1717 AXIS_DESCENDANT,
1718 AXIS_DESCENDANT_OR_SELF,
1719 AXIS_FOLLOWING,
1720 AXIS_FOLLOWING_SIBLING,
1721 AXIS_NAMESPACE,
1722 AXIS_PARENT,
1723 AXIS_PRECEDING,
1724 AXIS_PRECEDING_SIBLING,
1725 AXIS_SELF
1726} xmlXPathAxisVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001727
1728/*
1729 * A traversal function enumerates nodes along an axis.
1730 * Initially it must be called with NULL, and it indicates
1731 * termination on the axis by returning NULL.
1732 */
1733typedef xmlNodePtr (*xmlXPathTraversalFunction)
1734 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1735
1736/**
1737 * mlXPathNextSelf:
1738 * @ctxt: the XPath Parser context
1739 * @cur: the current node in the traversal
1740 *
1741 * Traversal function for the "self" direction
1742 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001743 *
1744 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001745 */
1746xmlNodePtr
1747xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1748 if (cur == NULL)
1749 return(ctxt->context->node);
1750 return(NULL);
1751}
1752
1753/**
1754 * mlXPathNextChild:
1755 * @ctxt: the XPath Parser context
1756 * @cur: the current node in the traversal
1757 *
1758 * Traversal function for the "child" direction
1759 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001760 *
1761 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001762 */
1763xmlNodePtr
1764xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001765 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001766 if (ctxt->context->node == NULL) return(NULL);
1767 switch (ctxt->context->node->type) {
1768 case XML_ELEMENT_NODE:
1769 case XML_TEXT_NODE:
1770 case XML_CDATA_SECTION_NODE:
1771 case XML_ENTITY_REF_NODE:
1772 case XML_ENTITY_NODE:
1773 case XML_PI_NODE:
1774 case XML_COMMENT_NODE:
1775 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001776 case XML_DTD_NODE:
1777 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001778 case XML_DOCUMENT_NODE:
1779 case XML_DOCUMENT_TYPE_NODE:
1780 case XML_DOCUMENT_FRAG_NODE:
1781 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00001782#ifdef LIBXML_SGML_ENABLED
1783 case XML_SGML_DOCUMENT_NODE:
1784#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001785 return(((xmlDocPtr) ctxt->context->node)->children);
1786 case XML_ELEMENT_DECL:
1787 case XML_ATTRIBUTE_DECL:
1788 case XML_ENTITY_DECL:
1789 case XML_ATTRIBUTE_NODE:
1790 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001791 }
1792 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001793 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001794 if ((cur->type == XML_DOCUMENT_NODE) ||
1795 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001796 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001797 return(cur->next);
1798}
1799
1800/**
1801 * mlXPathNextDescendant:
1802 * @ctxt: the XPath Parser context
1803 * @cur: the current node in the traversal
1804 *
1805 * Traversal function for the "descendant" direction
1806 * the descendant axis contains the descendants of the context node in document
1807 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001808 *
1809 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001810 */
1811xmlNodePtr
1812xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001813 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001814 if (ctxt->context->node == NULL)
1815 return(NULL);
1816 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1817 return(NULL);
1818
Daniel Veillardb05deb71999-08-10 19:04:08 +00001819 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00001820 return(ctxt->context->doc->children);
1821 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001822 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001823
Daniel Veillardbe803962000-06-28 23:40:59 +00001824 if (cur->children != NULL)
1825 {
1826 if (cur->children->type != XML_ENTITY_DECL)
1827 return(cur->children);
1828 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001829 if (cur->next != NULL) return(cur->next);
1830
1831 do {
1832 cur = cur->parent;
1833 if (cur == NULL) return(NULL);
1834 if (cur == ctxt->context->node) return(NULL);
1835 if (cur->next != NULL) {
1836 cur = cur->next;
1837 return(cur);
1838 }
1839 } while (cur != NULL);
1840 return(cur);
1841}
1842
1843/**
1844 * mlXPathNextDescendantOrSelf:
1845 * @ctxt: the XPath Parser context
1846 * @cur: the current node in the traversal
1847 *
1848 * Traversal function for the "descendant-or-self" direction
1849 * the descendant-or-self axis contains the context node and the descendants
1850 * of the context node in document order; thus the context node is the first
1851 * node on the axis, and the first child of the context node is the second node
1852 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001853 *
1854 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001855 */
1856xmlNodePtr
1857xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001858 if (cur == NULL) {
1859 if (ctxt->context->node == NULL)
1860 return(NULL);
1861 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1862 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001863 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001864 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001865
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001866 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001867}
1868
1869/**
1870 * xmlXPathNextParent:
1871 * @ctxt: the XPath Parser context
1872 * @cur: the current node in the traversal
1873 *
1874 * Traversal function for the "parent" direction
1875 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001876 *
1877 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001878 */
1879xmlNodePtr
1880xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1881 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001882 * the parent of an attribute or namespace node is the element
1883 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001884 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001885 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001886 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001887 if (ctxt->context->node == NULL) return(NULL);
1888 switch (ctxt->context->node->type) {
1889 case XML_ELEMENT_NODE:
1890 case XML_TEXT_NODE:
1891 case XML_CDATA_SECTION_NODE:
1892 case XML_ENTITY_REF_NODE:
1893 case XML_ENTITY_NODE:
1894 case XML_PI_NODE:
1895 case XML_COMMENT_NODE:
1896 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001897 case XML_DTD_NODE:
1898 case XML_ELEMENT_DECL:
1899 case XML_ATTRIBUTE_DECL:
1900 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001901 if (ctxt->context->node->parent == NULL)
1902 return((xmlNodePtr) ctxt->context->doc);
1903 return(ctxt->context->node->parent);
1904 case XML_ATTRIBUTE_NODE: {
1905 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1906
Daniel Veillardcf461992000-03-14 18:30:20 +00001907 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001908 }
1909 case XML_DOCUMENT_NODE:
1910 case XML_DOCUMENT_TYPE_NODE:
1911 case XML_DOCUMENT_FRAG_NODE:
1912 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00001913#ifdef LIBXML_SGML_ENABLED
1914 case XML_SGML_DOCUMENT_NODE:
1915#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001916 return(NULL);
1917 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001918 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001919 return(NULL);
1920}
1921
1922/**
1923 * xmlXPathNextAncestor:
1924 * @ctxt: the XPath Parser context
1925 * @cur: the current node in the traversal
1926 *
1927 * Traversal function for the "ancestor" direction
1928 * the ancestor axis contains the ancestors of the context node; the ancestors
1929 * of the context node consist of the parent of context node and the parent's
1930 * parent and so on; the nodes are ordered in reverse document order; thus the
1931 * parent is the first node on the axis, and the parent's parent is the second
1932 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001933 *
1934 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001935 */
1936xmlNodePtr
1937xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1938 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001939 * the parent of an attribute or namespace node is the element
1940 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001941 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001942 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001943 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001944 if (ctxt->context->node == NULL) return(NULL);
1945 switch (ctxt->context->node->type) {
1946 case XML_ELEMENT_NODE:
1947 case XML_TEXT_NODE:
1948 case XML_CDATA_SECTION_NODE:
1949 case XML_ENTITY_REF_NODE:
1950 case XML_ENTITY_NODE:
1951 case XML_PI_NODE:
1952 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001953 case XML_DTD_NODE:
1954 case XML_ELEMENT_DECL:
1955 case XML_ATTRIBUTE_DECL:
1956 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001957 case XML_NOTATION_NODE:
1958 if (ctxt->context->node->parent == NULL)
1959 return((xmlNodePtr) ctxt->context->doc);
1960 return(ctxt->context->node->parent);
1961 case XML_ATTRIBUTE_NODE: {
1962 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
1963
Daniel Veillardcf461992000-03-14 18:30:20 +00001964 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001965 }
1966 case XML_DOCUMENT_NODE:
1967 case XML_DOCUMENT_TYPE_NODE:
1968 case XML_DOCUMENT_FRAG_NODE:
1969 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00001970#ifdef LIBXML_SGML_ENABLED
1971 case XML_SGML_DOCUMENT_NODE:
1972#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001973 return(NULL);
1974 }
1975 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001976 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001977 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00001978 return((xmlNodePtr) ctxt->context->doc);
1979 if (cur == (xmlNodePtr) ctxt->context->doc)
1980 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001981 switch (cur->type) {
1982 case XML_ELEMENT_NODE:
1983 case XML_TEXT_NODE:
1984 case XML_CDATA_SECTION_NODE:
1985 case XML_ENTITY_REF_NODE:
1986 case XML_ENTITY_NODE:
1987 case XML_PI_NODE:
1988 case XML_COMMENT_NODE:
1989 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001990 case XML_DTD_NODE:
1991 case XML_ELEMENT_DECL:
1992 case XML_ATTRIBUTE_DECL:
1993 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001994 return(cur->parent);
1995 case XML_ATTRIBUTE_NODE: {
1996 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1997
Daniel Veillardcf461992000-03-14 18:30:20 +00001998 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001999 }
2000 case XML_DOCUMENT_NODE:
2001 case XML_DOCUMENT_TYPE_NODE:
2002 case XML_DOCUMENT_FRAG_NODE:
2003 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002004#ifdef LIBXML_SGML_ENABLED
2005 case XML_SGML_DOCUMENT_NODE:
2006#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002007 return(NULL);
2008 }
2009 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002010}
2011
2012/**
2013 * xmlXPathNextAncestorOrSelf:
2014 * @ctxt: the XPath Parser context
2015 * @cur: the current node in the traversal
2016 *
2017 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00002018 * he ancestor-or-self axis contains the context node and ancestors of
2019 * the context node in reverse document order; thus the context node is
2020 * the first node on the axis, and the context node's parent the second;
2021 * parent here is defined the same as with the parent axis.
2022 *
2023 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002024 */
2025xmlNodePtr
2026xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002027 if (cur == NULL)
2028 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002029 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002030}
2031
2032/**
2033 * xmlXPathNextFollowingSibling:
2034 * @ctxt: the XPath Parser context
2035 * @cur: the current node in the traversal
2036 *
2037 * Traversal function for the "following-sibling" direction
2038 * The following-sibling axis contains the following siblings of the context
2039 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002040 *
2041 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002042 */
2043xmlNodePtr
2044xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002045 if (cur == (xmlNodePtr) ctxt->context->doc)
2046 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002047 if (cur == NULL)
2048 return(ctxt->context->node->next);
2049 return(cur->next);
2050}
2051
2052/**
2053 * xmlXPathNextPrecedingSibling:
2054 * @ctxt: the XPath Parser context
2055 * @cur: the current node in the traversal
2056 *
2057 * Traversal function for the "preceding-sibling" direction
2058 * The preceding-sibling axis contains the preceding siblings of the context
2059 * node in reverse document order; the first preceding sibling is first on the
2060 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002061 *
2062 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002063 */
2064xmlNodePtr
2065xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002066 if (cur == (xmlNodePtr) ctxt->context->doc)
2067 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002068 if (cur == NULL)
2069 return(ctxt->context->node->prev);
2070 return(cur->prev);
2071}
2072
2073/**
2074 * xmlXPathNextFollowing:
2075 * @ctxt: the XPath Parser context
2076 * @cur: the current node in the traversal
2077 *
2078 * Traversal function for the "following" direction
2079 * The following axis contains all nodes in the same document as the context
2080 * node that are after the context node in document order, excluding any
2081 * descendants and excluding attribute nodes and namespace nodes; the nodes
2082 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00002083 *
2084 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002085 */
2086xmlNodePtr
2087xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002088 if (cur != NULL && cur->children != NULL)
2089 return cur->children ;
Daniel Veillardac260302000-10-04 13:33:43 +00002090 if (cur == NULL) cur = ctxt->context->node;
2091 if (cur == NULL) return(NULL) ; /* ERROR */
2092 if (cur->next != NULL) return(cur->next) ;
Daniel Veillard740abf52000-10-02 23:04:54 +00002093 do {
2094 cur = cur->parent;
2095 if (cur == NULL) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002096 if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */
2097 if (cur->next != NULL) return(cur->next);
Daniel Veillard740abf52000-10-02 23:04:54 +00002098 } while (cur != NULL);
2099 return(cur);
2100}
2101
2102/*
Daniel Veillardac260302000-10-04 13:33:43 +00002103 * xmlXPathIsAncestor:
2104 * @ancestor: the ancestor node
2105 * @node: the current node
2106 *
2107 * Check that @ancestor is a @node's ancestor
2108 *
Daniel Veillard740abf52000-10-02 23:04:54 +00002109 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2110 */
2111static int
Daniel Veillardac260302000-10-04 13:33:43 +00002112xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002113 xmlNodePtr tmp ;
2114 if (ancestor == NULL || node == NULL) return 0 ;
2115 for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) {
2116 if (tmp->parent == ancestor)
2117 return 1 ;
2118 }
2119 return 0 ;
2120}
2121
2122/**
2123 * xmlXPathNextPreceding:
2124 * @ctxt: the XPath Parser context
2125 * @cur: the current node in the traversal
2126 *
2127 * Traversal function for the "preceding" direction
2128 * the preceding axis contains all nodes in the same document as the context
2129 * node that are before the context node in document order, excluding any
2130 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2131 * ordered in reverse document order
2132 *
2133 * Returns the next element following that axis
2134 */
2135xmlNodePtr
2136xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2137 if (cur == NULL)
2138 cur = ctxt->context->node ;
2139 do {
2140 if (cur->prev != NULL) {
2141 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2142 ;
2143 return(cur) ;
2144 }
2145
2146 cur = cur->parent;
2147 if (cur == NULL) return(NULL);
2148 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002149 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillard740abf52000-10-02 23:04:54 +00002150 return(cur);
2151}
2152
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002153/**
2154 * xmlXPathNextNamespace:
2155 * @ctxt: the XPath Parser context
2156 * @cur: the current attribute in the traversal
2157 *
2158 * Traversal function for the "namespace" direction
2159 * the namespace axis contains the namespace nodes of the context node;
2160 * the order of nodes on this axis is implementation-defined; the axis will
2161 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00002162 *
2163 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002164 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00002165xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002166xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002167 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2168 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002169 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002170 ctxt->context->namespaces =
2171 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2172 if (ctxt->context->namespaces == NULL) return(NULL);
2173 ctxt->context->nsNr = 0;
2174 }
2175 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002176}
2177
2178/**
2179 * xmlXPathNextAttribute:
2180 * @ctxt: the XPath Parser context
2181 * @cur: the current attribute in the traversal
2182 *
2183 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00002184 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00002185 *
2186 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002187 */
2188xmlAttrPtr
2189xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00002190 if (cur == NULL) {
2191 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2192 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002193 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002194 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002195 return(cur->next);
2196}
2197
2198/************************************************************************
2199 * *
2200 * NodeTest Functions *
2201 * *
2202 ************************************************************************/
2203
Daniel Veillard740abf52000-10-02 23:04:54 +00002204typedef enum {
2205 NODE_TEST_NONE = 0,
2206 NODE_TEST_TYPE = 1,
2207 NODE_TEST_PI = 2,
2208 NODE_TEST_ALL = 3,
2209 NODE_TEST_NS = 4,
2210 NODE_TEST_NAME = 5
2211} xmlXPathTestVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002212
Daniel Veillard740abf52000-10-02 23:04:54 +00002213typedef enum {
Daniel Veillard55b91f22000-10-05 16:30:11 +00002214 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
2215 NODE_TYPE_TEXT = XML_TEXT_NODE,
2216 NODE_TYPE_PI = XML_PI_NODE,
2217 NODE_TYPE_NODE = XML_ELEMENT_NODE
Daniel Veillard740abf52000-10-02 23:04:54 +00002218} xmlXPathTypeVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002219
2220#define IS_FUNCTION 200
2221
2222/**
2223 * xmlXPathNodeCollectAndTest:
2224 * @ctxt: the XPath Parser context
Daniel Veillard740abf52000-10-02 23:04:54 +00002225 * @axis: the XPath axis
2226 * @test: the XPath test
2227 * @type: the XPath type
2228 * @prefix: the namesapce prefix if any
2229 * @name: the name used in the search if any
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002230 *
2231 * This is the function implementing a step: based on the current list
2232 * of nodes, it builds up a new list, looking at all nodes under that
2233 * axis and selecting them.
2234 *
2235 * Returns the new NodeSet resulting from the search.
2236 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002237void
2238xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2239 xmlXPathTestVal test, xmlXPathTypeVal type,
2240 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002241#ifdef DEBUG_STEP
2242 int n = 0, t = 0;
2243#endif
2244 int i;
2245 xmlNodeSetPtr ret;
2246 xmlXPathTraversalFunction next = NULL;
2247 xmlNodePtr cur = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00002248 xmlXPathObjectPtr obj;
2249 xmlNodeSetPtr nodelist;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002250
Daniel Veillard740abf52000-10-02 23:04:54 +00002251 CHECK_TYPE(XPATH_NODESET);
2252 obj = valuePop(ctxt);
2253
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002254#ifdef DEBUG_STEP
2255 fprintf(xmlXPathDebug, "new step : ");
2256#endif
2257 switch (axis) {
2258 case AXIS_ANCESTOR:
2259#ifdef DEBUG_STEP
2260 fprintf(xmlXPathDebug, "axis 'ancestors' ");
2261#endif
2262 next = xmlXPathNextAncestor; break;
2263 case AXIS_ANCESTOR_OR_SELF:
2264#ifdef DEBUG_STEP
2265 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
2266#endif
2267 next = xmlXPathNextAncestorOrSelf; break;
2268 case AXIS_ATTRIBUTE:
2269#ifdef DEBUG_STEP
2270 fprintf(xmlXPathDebug, "axis 'attributes' ");
2271#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002272 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002273 break;
2274 case AXIS_CHILD:
2275#ifdef DEBUG_STEP
2276 fprintf(xmlXPathDebug, "axis 'child' ");
2277#endif
2278 next = xmlXPathNextChild; break;
2279 case AXIS_DESCENDANT:
2280#ifdef DEBUG_STEP
2281 fprintf(xmlXPathDebug, "axis 'descendant' ");
2282#endif
2283 next = xmlXPathNextDescendant; break;
2284 case AXIS_DESCENDANT_OR_SELF:
2285#ifdef DEBUG_STEP
2286 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
2287#endif
2288 next = xmlXPathNextDescendantOrSelf; break;
2289 case AXIS_FOLLOWING:
2290#ifdef DEBUG_STEP
2291 fprintf(xmlXPathDebug, "axis 'following' ");
2292#endif
2293 next = xmlXPathNextFollowing; break;
2294 case AXIS_FOLLOWING_SIBLING:
2295#ifdef DEBUG_STEP
2296 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
2297#endif
2298 next = xmlXPathNextFollowingSibling; break;
2299 case AXIS_NAMESPACE:
2300#ifdef DEBUG_STEP
2301 fprintf(xmlXPathDebug, "axis 'namespace' ");
2302#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002303 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002304 break;
2305 case AXIS_PARENT:
2306#ifdef DEBUG_STEP
2307 fprintf(xmlXPathDebug, "axis 'parent' ");
2308#endif
2309 next = xmlXPathNextParent; break;
2310 case AXIS_PRECEDING:
2311#ifdef DEBUG_STEP
2312 fprintf(xmlXPathDebug, "axis 'preceding' ");
2313#endif
2314 next = xmlXPathNextPreceding; break;
2315 case AXIS_PRECEDING_SIBLING:
2316#ifdef DEBUG_STEP
2317 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
2318#endif
2319 next = xmlXPathNextPrecedingSibling; break;
2320 case AXIS_SELF:
2321#ifdef DEBUG_STEP
2322 fprintf(xmlXPathDebug, "axis 'self' ");
2323#endif
2324 next = xmlXPathNextSelf; break;
2325 }
Daniel Veillard740abf52000-10-02 23:04:54 +00002326 if (next == NULL)
2327 return;
2328
2329 nodelist = obj->nodesetval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002330 ret = xmlXPathNodeSetCreate(NULL);
2331#ifdef DEBUG_STEP
2332 fprintf(xmlXPathDebug, " context contains %d nodes\n",
Daniel Veillard740abf52000-10-02 23:04:54 +00002333 nodelist->nodeNr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002334 switch (test) {
2335 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002336 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002337 break;
2338 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002339 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002340 break;
2341 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002342 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002343 break;
2344 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002345 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002346 break;
2347 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002348 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002349 prefix);
2350 break;
2351 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002352 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002353 if (prefix != NULL)
2354 fprintf(xmlXPathDebug, " with namespace %s\n",
2355 prefix);
2356 break;
2357 }
2358 fprintf(xmlXPathDebug, "Testing : ");
2359#endif
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00002360 /*
2361 * 2.3 Node Tests
2362 * - For the attribute axis, the principal node type is attribute.
2363 * - For the namespace axis, the principal node type is namespace.
2364 * - For other axes, the principal node type is element.
2365 *
2366 * A node test * is true for any node of the
2367 * principal node type. For example, child::* willi
2368 * select all element children of the context node
2369 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002370 for (i = 0;i < nodelist->nodeNr; i++) {
2371 ctxt->context->node = nodelist->nodeTab[i];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002372
2373 cur = NULL;
2374 do {
2375 cur = next(ctxt, cur);
2376 if (cur == NULL) break;
2377#ifdef DEBUG_STEP
2378 t++;
2379 fprintf(xmlXPathDebug, " %s", cur->name);
2380#endif
2381 switch (test) {
2382 case NODE_TEST_NONE:
2383 STRANGE
Daniel Veillard740abf52000-10-02 23:04:54 +00002384 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002385 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002386 if ((cur->type == type) ||
2387 ((type == XML_ELEMENT_NODE) &&
2388 ((cur->type == XML_DOCUMENT_NODE) ||
2389 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002390#ifdef DEBUG_STEP
2391 n++;
2392#endif
2393 xmlXPathNodeSetAdd(ret, cur);
2394 }
2395 break;
2396 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002397 if (cur->type == XML_PI_NODE) {
2398 if ((name != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002399 (!xmlStrEqual(name, cur->name)))
Daniel Veillardb96e6431999-08-29 21:02:19 +00002400 break;
2401#ifdef DEBUG_STEP
2402 n++;
2403#endif
2404 xmlXPathNodeSetAdd(ret, cur);
2405 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002406 break;
2407 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002408 if ((cur->type == XML_ELEMENT_NODE) ||
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00002409 (cur->type == XML_DOCUMENT_NODE) ||
2410 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002411#ifdef DEBUG_STEP
2412 n++;
2413#endif
2414 xmlXPathNodeSetAdd(ret, cur);
2415 }
2416 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002417 case NODE_TEST_NS: {
2418 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002419 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002420 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002421 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002422 switch (cur->type) {
2423 case XML_ELEMENT_NODE:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002424 if (xmlStrEqual(name, cur->name) &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002425 (((prefix == NULL) ||
2426 ((cur->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002427 (xmlStrEqual(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002428#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002429 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002430#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002431 xmlXPathNodeSetAdd(ret, cur);
2432 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002433 break;
2434 case XML_ATTRIBUTE_NODE: {
2435 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002436 if (xmlStrEqual(name, attr->name)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002437#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002438 n++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002439#endif
2440 xmlXPathNodeSetAdd(ret, cur);
2441 }
2442 break;
2443 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002444 default:
2445 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002446 }
2447 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002448 }
2449 } while (cur != NULL);
2450 }
2451#ifdef DEBUG_STEP
2452 fprintf(xmlXPathDebug,
2453 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2454#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00002455 xmlXPathFreeObject(obj);
2456 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002457}
2458
2459
2460/************************************************************************
2461 * *
2462 * Implicit tree core function library *
2463 * *
2464 ************************************************************************/
2465
2466/**
2467 * xmlXPathRoot:
2468 * @ctxt: the XPath Parser context
2469 *
2470 * Initialize the context to the root of the document
2471 */
2472void
2473xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00002474 if (ctxt->value != NULL) {
2475 xmlXPathObjectPtr obj;
Daniel Veillard740abf52000-10-02 23:04:54 +00002476
Daniel Veillard55b91f22000-10-05 16:30:11 +00002477 CHECK_TYPE(XPATH_NODESET);
2478 obj = valuePop(ctxt);
2479 xmlXPathFreeObject(obj);
2480 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002481 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Daniel Veillard740abf52000-10-02 23:04:54 +00002482 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002483}
2484
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002485/************************************************************************
2486 * *
2487 * The explicit core function library *
2488 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2489 * *
2490 ************************************************************************/
2491
2492
2493/**
2494 * xmlXPathLastFunction:
2495 * @ctxt: the XPath Parser context
2496 *
2497 * Implement the last() XPath function
2498 * The last function returns the number of nodes in the context node list.
2499 */
2500void
2501xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2502 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002503 if (ctxt->context->contextSize > 0) {
2504 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
2505#ifdef DEBUG_EXPR
2506 fprintf(xmlXPathDebug, "last() : %d\n", ctxt->context->contextSize);
2507#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002508 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002509 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002510 }
2511}
2512
2513/**
2514 * xmlXPathPositionFunction:
2515 * @ctxt: the XPath Parser context
2516 *
2517 * Implement the position() XPath function
2518 * The position function returns the position of the context node in the
2519 * context node list. The first position is 1, and so the last positionr
2520 * will be equal to last().
2521 */
2522void
2523xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002524 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002525 if (ctxt->context->proximityPosition > 0) {
2526 valuePush(ctxt,
2527 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
2528#ifdef DEBUG_EXPR
2529 fprintf(xmlXPathDebug, "position() : %d\n",
2530 ctxt->context->proximityPosition);
2531#endif
2532 } else {
2533 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002534 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002535}
2536
2537/**
2538 * xmlXPathCountFunction:
2539 * @ctxt: the XPath Parser context
2540 *
2541 * Implement the count() XPath function
2542 */
2543void
2544xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2545 xmlXPathObjectPtr cur;
2546
2547 CHECK_ARITY(1);
2548 CHECK_TYPE(XPATH_NODESET);
2549 cur = valuePop(ctxt);
2550
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002551 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002552 xmlXPathFreeObject(cur);
2553}
2554
2555/**
2556 * xmlXPathIdFunction:
2557 * @ctxt: the XPath Parser context
2558 *
2559 * Implement the id() XPath function
2560 * The id function selects elements by their unique ID
2561 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2562 * then the result is the union of the result of applying id to the
2563 * string value of each of the nodes in the argument node-set. When the
2564 * argument to id is of any other type, the argument is converted to a
2565 * string as if by a call to the string function; the string is split
2566 * into a whitespace-separated list of tokens (whitespace is any sequence
2567 * of characters matching the production S); the result is a node-set
2568 * containing the elements in the same document as the context node that
2569 * have a unique ID equal to any of the tokens in the list.
2570 */
2571void
2572xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002573 const xmlChar *tokens;
2574 const xmlChar *cur;
2575 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002576 xmlAttrPtr attr;
2577 xmlNodePtr elem = NULL;
2578 xmlXPathObjectPtr ret, obj;
2579
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002580 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002581 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002582 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002583 if (obj->type == XPATH_NODESET) {
2584 TODO /* ID function in case of NodeSet */
2585 }
2586 if (obj->type != XPATH_STRING) {
2587 valuePush(ctxt, obj);
2588 xmlXPathStringFunction(ctxt, 1);
2589 obj = valuePop(ctxt);
2590 if (obj->type != XPATH_STRING) {
2591 xmlXPathFreeObject(obj);
2592 return;
2593 }
2594 }
2595 tokens = obj->stringval;
2596
2597 ret = xmlXPathNewNodeSet(NULL);
2598 valuePush(ctxt, ret);
2599 if (tokens == NULL) {
2600 xmlXPathFreeObject(obj);
2601 return;
2602 }
2603
2604 cur = tokens;
2605
2606 while (IS_BLANK(*cur)) cur++;
2607 while (*cur != 0) {
2608 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2609 (*cur == '.') || (*cur == '-') ||
2610 (*cur == '_') || (*cur == ':') ||
2611 (IS_COMBINING(*cur)) ||
2612 (IS_EXTENDER(*cur)))
2613 cur++;
2614
2615 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2616
2617 ID = xmlStrndup(tokens, cur - tokens);
2618 attr = xmlGetID(ctxt->context->doc, ID);
2619 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002620 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002621 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2622 }
2623 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002624 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002625
2626 while (IS_BLANK(*cur)) cur++;
2627 tokens = cur;
2628 }
2629 xmlXPathFreeObject(obj);
2630 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002631}
2632
2633/**
2634 * xmlXPathLocalPartFunction:
2635 * @ctxt: the XPath Parser context
2636 *
2637 * Implement the local-part() XPath function
2638 * The local-part function returns a string containing the local part
2639 * of the name of the node in the argument node-set that is first in
2640 * document order. If the node-set is empty or the first node has no
2641 * name, an empty string is returned. If the argument is omitted it
2642 * defaults to the context node.
2643 */
2644void
2645xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2646 xmlXPathObjectPtr cur;
2647
2648 CHECK_ARITY(1);
2649 CHECK_TYPE(XPATH_NODESET);
2650 cur = valuePop(ctxt);
2651
2652 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002653 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002654 } else {
2655 int i = 0; /* Should be first in document order !!!!! */
2656 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2657 }
2658 xmlXPathFreeObject(cur);
2659}
2660
2661/**
2662 * xmlXPathNamespaceFunction:
2663 * @ctxt: the XPath Parser context
2664 *
2665 * Implement the namespace() XPath function
2666 * The namespace function returns a string containing the namespace URI
2667 * of the expanded name of the node in the argument node-set that is
2668 * first in document order. If the node-set is empty, the first node has
2669 * no name, or the expanded name has no namespace URI, an empty string
2670 * is returned. If the argument is omitted it defaults to the context node.
2671 */
2672void
2673xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2674 xmlXPathObjectPtr cur;
2675
Daniel Veillardb96e6431999-08-29 21:02:19 +00002676 if (nargs == 0) {
2677 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2678 nargs = 1;
2679 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002680 CHECK_ARITY(1);
2681 CHECK_TYPE(XPATH_NODESET);
2682 cur = valuePop(ctxt);
2683
2684 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002685 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002686 } else {
2687 int i = 0; /* Should be first in document order !!!!! */
2688
2689 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002690 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002691 else
2692 valuePush(ctxt, xmlXPathNewString(
2693 cur->nodesetval->nodeTab[i]->ns->href));
2694 }
2695 xmlXPathFreeObject(cur);
2696}
2697
2698/**
2699 * xmlXPathNameFunction:
2700 * @ctxt: the XPath Parser context
2701 *
2702 * Implement the name() XPath function
2703 * The name function returns a string containing a QName representing
2704 * the name of the node in the argument node-set that is first in documenti
2705 * order. The QName must represent the name with respect to the namespace
2706 * declarations in effect on the node whose name is being represented.
2707 * Typically, this will be the form in which the name occurred in the XML
2708 * source. This need not be the case if there are namespace declarations
2709 * in effect on the node that associate multiple prefixes with the same
2710 * namespace. However, an implementation may include information about
2711 * the original prefix in its representation of nodes; in this case, an
2712 * implementation can ensure that the returned string is always the same
2713 * as the QName used in the XML source. If the argument it omitted it
2714 * defaults to the context node.
2715 * Libxml keep the original prefix so the "real qualified name" used is
2716 * returned.
2717 */
2718void
2719xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2720 xmlXPathObjectPtr cur;
2721
2722 CHECK_ARITY(1);
2723 CHECK_TYPE(XPATH_NODESET);
2724 cur = valuePop(ctxt);
2725
2726 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002727 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002728 } else {
2729 int i = 0; /* Should be first in document order !!!!! */
2730
2731 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2732 valuePush(ctxt, xmlXPathNewString(
2733 cur->nodesetval->nodeTab[i]->name));
2734
2735 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002736 char name[2000];
Daniel Veillard39c7d712000-09-10 16:14:55 +00002737#ifdef HAVE_SNPRINTF
2738 snprintf(name, sizeof(name), "%s:%s",
2739 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2740 (char *) cur->nodesetval->nodeTab[i]->name);
2741#else
Daniel Veillardb96e6431999-08-29 21:02:19 +00002742 sprintf(name, "%s:%s",
2743 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2744 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00002745#endif
2746 name[sizeof(name) - 1] = 0;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002747 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002748 }
2749 }
2750 xmlXPathFreeObject(cur);
2751}
2752
2753/**
2754 * xmlXPathStringFunction:
2755 * @ctxt: the XPath Parser context
2756 *
2757 * Implement the string() XPath function
2758 * he string function converts an object to a string as follows:
2759 * - A node-set is converted to a string by returning the value of
2760 * the node in the node-set that is first in document order.
2761 * If the node-set is empty, an empty string is returned.
2762 * - A number is converted to a string as follows
2763 * + NaN is converted to the string NaN
2764 * + positive zero is converted to the string 0
2765 * + negative zero is converted to the string 0
2766 * + positive infinity is converted to the string Infinity
2767 * + negative infinity is converted to the string -Infinity
2768 * + if the number is an integer, the number is represented in
2769 * decimal form as a Number with no decimal point and no leading
2770 * zeros, preceded by a minus sign (-) if the number is negative
2771 * + otherwise, the number is represented in decimal form as a
2772 * Number including a decimal point with at least one digit
2773 * before the decimal point and at least one digit after the
2774 * decimal point, preceded by a minus sign (-) if the number
2775 * is negative; there must be no leading zeros before the decimal
2776 * point apart possibly from the one required digit immediatelyi
2777 * before the decimal point; beyond the one required digit
2778 * after the decimal point there must be as many, but only as
2779 * many, more digits as are needed to uniquely distinguish the
2780 * number from all other IEEE 754 numeric values.
2781 * - The boolean false value is converted to the string false.
2782 * The boolean true value is converted to the string true.
2783 */
2784void
2785xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2786 xmlXPathObjectPtr cur;
2787
2788 CHECK_ARITY(1);
2789 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002790 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002791 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002792 case XPATH_UNDEFINED:
2793#ifdef DEBUG_EXPR
2794 fprintf(xmlXPathDebug, "String: undefined\n");
2795#endif
2796 valuePush(ctxt, xmlXPathNewCString(""));
2797 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002798 case XPATH_NODESET:
2799 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002800 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002801 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002802 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002803 int i = 0; /* Should be first in document order !!!!! */
2804 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2805 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002806 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002807 }
2808 xmlXPathFreeObject(cur);
2809 return;
2810 case XPATH_STRING:
2811 valuePush(ctxt, cur);
2812 return;
2813 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002814 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2815 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002816 xmlXPathFreeObject(cur);
2817 return;
2818 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002819 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002820
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002821 if (isnan(cur->floatval))
2822 sprintf(buf, "NaN");
2823 else if (isinf(cur->floatval) > 0)
2824 sprintf(buf, "+Infinity");
2825 else if (isinf(cur->floatval) < 0)
2826 sprintf(buf, "-Infinity");
2827 else
2828 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002829 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002830 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002831 return;
2832 }
Daniel Veillard740abf52000-10-02 23:04:54 +00002833 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002834 case XPATH_POINT:
2835 case XPATH_RANGE:
2836 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002837 TODO
2838 valuePush(ctxt, xmlXPathNewCString(""));
2839 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002840 }
2841 STRANGE
2842}
2843
2844/**
2845 * xmlXPathStringLengthFunction:
2846 * @ctxt: the XPath Parser context
2847 *
2848 * Implement the string-length() XPath function
2849 * The string-length returns the number of characters in the string
2850 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2851 * the context node converted to a string, in other words the value
2852 * of the context node.
2853 */
2854void
2855xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2856 xmlXPathObjectPtr cur;
2857
2858 if (nargs == 0) {
2859 if (ctxt->context->node == NULL) {
2860 valuePush(ctxt, xmlXPathNewFloat(0));
2861 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002862 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002863
2864 content = xmlNodeGetContent(ctxt->context->node);
2865 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002866 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002867 }
2868 return;
2869 }
2870 CHECK_ARITY(1);
2871 CHECK_TYPE(XPATH_STRING);
2872 cur = valuePop(ctxt);
2873 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2874 xmlXPathFreeObject(cur);
2875}
2876
2877/**
2878 * xmlXPathConcatFunction:
2879 * @ctxt: the XPath Parser context
2880 *
2881 * Implement the concat() XPath function
2882 * The concat function returns the concatenation of its arguments.
2883 */
2884void
2885xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002886 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002887 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002888
2889 if (nargs < 2) {
2890 CHECK_ARITY(2);
2891 }
2892
2893 cur = valuePop(ctxt);
2894 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2895 xmlXPathFreeObject(cur);
2896 return;
2897 }
2898 nargs--;
2899
2900 while (nargs > 0) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002901 newobj = valuePop(ctxt);
2902 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
2903 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002904 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002905 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002906 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002907 tmp = xmlStrcat(newobj->stringval, cur->stringval);
2908 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002909 cur->stringval = tmp;
2910
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002911 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002912 nargs--;
2913 }
2914 valuePush(ctxt, cur);
2915}
2916
2917/**
2918 * xmlXPathContainsFunction:
2919 * @ctxt: the XPath Parser context
2920 *
2921 * Implement the contains() XPath function
2922 * The contains function returns true if the first argument string
2923 * contains the second argument string, and otherwise returns false.
2924 */
2925void
2926xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2927 xmlXPathObjectPtr hay, needle;
2928
2929 CHECK_ARITY(2);
2930 CHECK_TYPE(XPATH_STRING);
2931 needle = valuePop(ctxt);
2932 hay = valuePop(ctxt);
2933 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2934 xmlXPathFreeObject(hay);
2935 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002936 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002937 }
2938 if (xmlStrstr(hay->stringval, needle->stringval))
2939 valuePush(ctxt, xmlXPathNewBoolean(1));
2940 else
2941 valuePush(ctxt, xmlXPathNewBoolean(0));
2942 xmlXPathFreeObject(hay);
2943 xmlXPathFreeObject(needle);
2944}
2945
2946/**
2947 * xmlXPathStartsWithFunction:
2948 * @ctxt: the XPath Parser context
2949 *
2950 * Implement the starts-with() XPath function
2951 * The starts-with function returns true if the first argument string
2952 * starts with the second argument string, and otherwise returns false.
2953 */
2954void
2955xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2956 xmlXPathObjectPtr hay, needle;
2957 int n;
2958
2959 CHECK_ARITY(2);
2960 CHECK_TYPE(XPATH_STRING);
2961 needle = valuePop(ctxt);
2962 hay = valuePop(ctxt);
2963 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2964 xmlXPathFreeObject(hay);
2965 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002966 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002967 }
2968 n = xmlStrlen(needle->stringval);
2969 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2970 valuePush(ctxt, xmlXPathNewBoolean(0));
2971 else
2972 valuePush(ctxt, xmlXPathNewBoolean(1));
2973 xmlXPathFreeObject(hay);
2974 xmlXPathFreeObject(needle);
2975}
2976
2977/**
2978 * xmlXPathSubstringFunction:
2979 * @ctxt: the XPath Parser context
2980 *
2981 * Implement the substring() XPath function
2982 * The substring function returns the substring of the first argument
2983 * starting at the position specified in the second argument with
2984 * length specified in the third argument. For example,
2985 * substring("12345",2,3) returns "234". If the third argument is not
2986 * specified, it returns the substring starting at the position specified
2987 * in the second argument and continuing to the end of the string. For
2988 * example, substring("12345",2) returns "2345". More precisely, each
2989 * character in the string (see [3.6 Strings]) is considered to have a
2990 * numeric position: the position of the first character is 1, the position
2991 * of the second character is 2 and so on. The returned substring contains
2992 * those characters for which the position of the character is greater than
2993 * or equal to the second argument and, if the third argument is specified,
2994 * less than the sum of the second and third arguments; the comparisons
2995 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2996 * - substring("12345", 1.5, 2.6) returns "234"
2997 * - substring("12345", 0, 3) returns "12"
2998 * - substring("12345", 0 div 0, 3) returns ""
2999 * - substring("12345", 1, 0 div 0) returns ""
3000 * - substring("12345", -42, 1 div 0) returns "12345"
3001 * - substring("12345", -1 div 0, 1 div 0) returns ""
3002 */
3003void
3004xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3005 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003006 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003007 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003008 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003009
3010 /*
3011 * Conformance needs to be checked !!!!!
3012 */
3013 if (nargs < 2) {
3014 CHECK_ARITY(2);
3015 }
3016 if (nargs > 3) {
3017 CHECK_ARITY(3);
3018 }
3019 if (nargs == 3) {
3020 CHECK_TYPE(XPATH_NUMBER);
3021 len = valuePop(ctxt);
3022 le = len->floatval;
3023 xmlXPathFreeObject(len);
3024 } else {
3025 le = 2000000000;
3026 }
3027 CHECK_TYPE(XPATH_NUMBER);
3028 start = valuePop(ctxt);
3029 in = start->floatval;
3030 xmlXPathFreeObject(start);
3031 CHECK_TYPE(XPATH_STRING);
3032 str = valuePop(ctxt);
3033 le += in;
3034
3035 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003036 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003037 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003038
3039 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003040 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003041 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003042
3043 /* back to a zero based len */
3044 i--;
3045 l--;
3046
3047 /* check against the string len */
3048 if (l > 1024) {
3049 l = xmlStrlen(str->stringval);
3050 }
3051 if (i < 0) {
3052 i = 0;
3053 }
3054
3055 /* number of chars to copy */
3056 l -= i;
3057
3058 ret = xmlStrsub(str->stringval, i, l);
3059 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00003060 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003061 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003062 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003063 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003064 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003065 xmlXPathFreeObject(str);
3066}
3067
3068/**
3069 * xmlXPathSubstringBeforeFunction:
3070 * @ctxt: the XPath Parser context
3071 *
3072 * Implement the substring-before() XPath function
3073 * The substring-before function returns the substring of the first
3074 * argument string that precedes the first occurrence of the second
3075 * argument string in the first argument string, or the empty string
3076 * if the first argument string does not contain the second argument
3077 * string. For example, substring-before("1999/04/01","/") returns 1999.
3078 */
3079void
3080xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003081 xmlXPathObjectPtr str;
3082 xmlXPathObjectPtr find;
3083 xmlBufferPtr target;
3084 const xmlChar *point;
3085 int offset;
3086
3087 CHECK_ARITY(2);
3088 find = valuePop(ctxt);
3089 str = valuePop(ctxt);
3090
3091 target = xmlBufferCreate();
3092 if (target) {
3093 point = xmlStrstr(str->stringval, find->stringval);
3094 if (point) {
3095 offset = (int)(point - str->stringval);
3096 xmlBufferAdd(target, str->stringval, offset);
3097 }
3098 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3099 xmlBufferFree(target);
3100 }
3101
3102 xmlXPathFreeObject(str);
3103 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003104}
3105
3106/**
3107 * xmlXPathSubstringAfterFunction:
3108 * @ctxt: the XPath Parser context
3109 *
3110 * Implement the substring-after() XPath function
3111 * The substring-after function returns the substring of the first
3112 * argument string that follows the first occurrence of the second
3113 * argument string in the first argument string, or the empty stringi
3114 * if the first argument string does not contain the second argument
3115 * string. For example, substring-after("1999/04/01","/") returns 04/01,
3116 * and substring-after("1999/04/01","19") returns 99/04/01.
3117 */
3118void
3119xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003120 xmlXPathObjectPtr str;
3121 xmlXPathObjectPtr find;
3122 xmlBufferPtr target;
3123 const xmlChar *point;
3124 int offset;
3125
3126 CHECK_ARITY(2);
3127 find = valuePop(ctxt);
3128 str = valuePop(ctxt);
3129
3130 target = xmlBufferCreate();
3131 if (target) {
3132 point = xmlStrstr(str->stringval, find->stringval);
3133 if (point) {
3134 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
3135 xmlBufferAdd(target, &str->stringval[offset],
3136 xmlStrlen(str->stringval) - offset);
3137 }
3138 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3139 xmlBufferFree(target);
3140 }
3141
3142 xmlXPathFreeObject(str);
3143 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003144}
3145
3146/**
3147 * xmlXPathNormalizeFunction:
3148 * @ctxt: the XPath Parser context
3149 *
3150 * Implement the normalize() XPath function
3151 * The normalize function returns the argument string with white
3152 * space normalized by stripping leading and trailing whitespace
3153 * and replacing sequences of whitespace characters by a single
3154 * space. Whitespace characters are the same allowed by the S production
3155 * in XML. If the argument is omitted, it defaults to the context
3156 * node converted to a string, in other words the value of the context node.
3157 */
3158void
3159xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003160 xmlXPathObjectPtr obj = NULL;
3161 xmlChar *source = NULL;
3162 xmlBufferPtr target;
3163 xmlChar blank;
3164
3165 if (nargs < 1) {
3166 /* Use current context node */
3167 CHECK_ARITY(0);
3168 TODO /* source = xmlNodeGetContent(ctxt->context->node); */
3169 } else if (nargs >= 1) {
3170 /* Use argument */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003171 CHECK_ARITY(1);
Daniel Veillard46057e12000-09-24 18:49:59 +00003172 obj = valuePop(ctxt);
3173 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3174 source = obj->stringval;
3175 }
3176 target = xmlBufferCreate();
3177 if (target && source) {
3178
3179 /* Skip leading whitespaces */
3180 while (IS_BLANK(*source))
3181 source++;
3182
3183 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
3184 blank = 0;
3185 while (*source) {
3186 if (IS_BLANK(*source)) {
3187 blank = *source;
3188 } else {
3189 if (blank) {
3190 xmlBufferAdd(target, &blank, 1);
3191 blank = 0;
3192 }
3193 xmlBufferAdd(target, source, 1);
3194 }
3195 source++;
3196 }
3197
3198 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3199 xmlBufferFree(target);
3200 }
3201 if (obj)
3202 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003203}
3204
3205/**
3206 * xmlXPathTranslateFunction:
3207 * @ctxt: the XPath Parser context
3208 *
3209 * Implement the translate() XPath function
3210 * The translate function returns the first argument string with
3211 * occurrences of characters in the second argument string replaced
3212 * by the character at the corresponding position in the third argument
3213 * string. For example, translate("bar","abc","ABC") returns the string
3214 * BAr. If there is a character in the second argument string with no
3215 * character at a corresponding position in the third argument string
3216 * (because the second argument string is longer than the third argument
3217 * string), then occurrences of that character in the first argument
3218 * string are removed. For example, translate("--aaa--","abc-","ABC")
3219 * returns "AAA". If a character occurs more than once in second
3220 * argument string, then the first occurrence determines the replacement
3221 * character. If the third argument string is longer than the second
3222 * argument string, then excess characters are ignored.
3223 */
3224void
3225xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003226 xmlXPathObjectPtr str;
3227 xmlXPathObjectPtr from;
3228 xmlXPathObjectPtr to;
3229 xmlBufferPtr target;
3230 int i, offset, max;
3231 xmlChar ch;
3232 const xmlChar *point;
3233
3234 CHECK_ARITY(3);
3235
3236 to = valuePop(ctxt);
3237 from = valuePop(ctxt);
3238 str = valuePop(ctxt);
3239
3240 target = xmlBufferCreate();
3241 if (target) {
3242 max = xmlStrlen(to->stringval);
3243 for (i = 0; (ch = str->stringval[i]); i++) {
3244 point = xmlStrchr(from->stringval, ch);
3245 if (point) {
3246 /* Warning: This may not work with UTF-8 */
3247 offset = (int)(point - from->stringval);
3248 if (offset < max)
3249 xmlBufferAdd(target, &to->stringval[offset], 1);
3250 } else
3251 xmlBufferAdd(target, &ch, 1);
3252 }
3253 }
3254 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3255 xmlBufferFree(target);
3256 xmlXPathFreeObject(str);
3257 xmlXPathFreeObject(from);
3258 xmlXPathFreeObject(to);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003259}
3260
3261/**
3262 * xmlXPathBooleanFunction:
3263 * @ctxt: the XPath Parser context
3264 *
3265 * Implement the boolean() XPath function
3266 * he boolean function converts its argument to a boolean as follows:
3267 * - a number is true if and only if it is neither positive or
3268 * negative zero nor NaN
3269 * - a node-set is true if and only if it is non-empty
3270 * - a string is true if and only if its length is non-zero
3271 */
3272void
3273xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3274 xmlXPathObjectPtr cur;
3275 int res = 0;
3276
3277 CHECK_ARITY(1);
3278 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003279 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003280 switch (cur->type) {
3281 case XPATH_NODESET:
3282 if ((cur->nodesetval == NULL) ||
3283 (cur->nodesetval->nodeNr == 0)) res = 0;
3284 else
3285 res = 1;
3286 break;
3287 case XPATH_STRING:
3288 if ((cur->stringval == NULL) ||
3289 (cur->stringval[0] == 0)) res = 0;
3290 else
3291 res = 1;
3292 break;
3293 case XPATH_BOOLEAN:
3294 valuePush(ctxt, cur);
3295 return;
3296 case XPATH_NUMBER:
3297 if (cur->floatval) res = 1;
3298 break;
3299 default:
3300 STRANGE
3301 }
3302 xmlXPathFreeObject(cur);
3303 valuePush(ctxt, xmlXPathNewBoolean(res));
3304}
3305
3306/**
3307 * xmlXPathNotFunction:
3308 * @ctxt: the XPath Parser context
3309 *
3310 * Implement the not() XPath function
3311 * The not function returns true if its argument is false,
3312 * and false otherwise.
3313 */
3314void
3315xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3316 CHECK_ARITY(1);
3317 CHECK_TYPE(XPATH_BOOLEAN);
3318 ctxt->value->boolval = ! ctxt->value->boolval;
3319}
3320
3321/**
3322 * xmlXPathTrueFunction:
3323 * @ctxt: the XPath Parser context
3324 *
3325 * Implement the true() XPath function
3326 */
3327void
3328xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3329 CHECK_ARITY(0);
3330 valuePush(ctxt, xmlXPathNewBoolean(1));
3331}
3332
3333/**
3334 * xmlXPathFalseFunction:
3335 * @ctxt: the XPath Parser context
3336 *
3337 * Implement the false() XPath function
3338 */
3339void
3340xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3341 CHECK_ARITY(0);
3342 valuePush(ctxt, xmlXPathNewBoolean(0));
3343}
3344
3345/**
3346 * xmlXPathLangFunction:
3347 * @ctxt: the XPath Parser context
3348 *
3349 * Implement the lang() XPath function
3350 * The lang function returns true or false depending on whether the
3351 * language of the context node as specified by xml:lang attributes
3352 * is the same as or is a sublanguage of the language specified by
3353 * the argument string. The language of the context node is determined
3354 * by the value of the xml:lang attribute on the context node, or, if
3355 * the context node has no xml:lang attribute, by the value of the
3356 * xml:lang attribute on the nearest ancestor of the context node that
3357 * has an xml:lang attribute. If there is no such attribute, then lang
3358 * returns false. If there is such an attribute, then lang returns
3359 * true if the attribute value is equal to the argument ignoring case,
3360 * or if there is some suffix starting with - such that the attribute
3361 * value is equal to the argument ignoring that suffix of the attribute
3362 * value and ignoring case.
3363 */
3364void
3365xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003366 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003367 const xmlChar *theLang;
3368 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003369 int ret = 0;
3370 int i;
3371
3372 CHECK_ARITY(1);
3373 CHECK_TYPE(XPATH_STRING);
3374 val = valuePop(ctxt);
3375 lang = val->stringval;
3376 theLang = xmlNodeGetLang(ctxt->context->node);
3377 if ((theLang != NULL) && (lang != NULL)) {
3378 for (i = 0;lang[i] != 0;i++)
3379 if (toupper(lang[i]) != toupper(theLang[i]))
3380 goto not_equal;
3381 ret = 1;
3382 }
3383not_equal:
3384 xmlXPathFreeObject(val);
3385 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003386}
3387
3388/**
3389 * xmlXPathNumberFunction:
3390 * @ctxt: the XPath Parser context
3391 *
3392 * Implement the number() XPath function
3393 */
3394void
3395xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3396 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003397 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003398
3399 CHECK_ARITY(1);
3400 cur = valuePop(ctxt);
3401 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003402 case XPATH_UNDEFINED:
3403#ifdef DEBUG_EXPR
3404 fprintf(xmlXPathDebug, "NUMBER: undefined\n");
3405#endif
3406 valuePush(ctxt, xmlXPathNewFloat(0.0));
3407 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003408 case XPATH_NODESET:
3409 valuePush(ctxt, cur);
3410 xmlXPathStringFunction(ctxt, 1);
3411 cur = valuePop(ctxt);
3412 case XPATH_STRING:
3413 res = xmlXPathStringEvalNumber(cur->stringval);
3414 valuePush(ctxt, xmlXPathNewFloat(res));
3415 xmlXPathFreeObject(cur);
3416 return;
3417 case XPATH_BOOLEAN:
3418 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
3419 else valuePush(ctxt, xmlXPathNewFloat(0.0));
3420 xmlXPathFreeObject(cur);
3421 return;
3422 case XPATH_NUMBER:
3423 valuePush(ctxt, cur);
3424 return;
Daniel Veillard740abf52000-10-02 23:04:54 +00003425 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003426 case XPATH_POINT:
3427 case XPATH_RANGE:
3428 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003429 TODO
3430 valuePush(ctxt, xmlXPathNewFloat(0.0));
3431 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003432 }
3433 STRANGE
3434}
3435
3436/**
3437 * xmlXPathSumFunction:
3438 * @ctxt: the XPath Parser context
3439 *
3440 * Implement the sum() XPath function
3441 * The sum function returns the sum of the values of the nodes in
3442 * the argument node-set.
3443 */
3444void
3445xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3446 CHECK_ARITY(1);
3447 TODO /* BUG Sum : don't understand the definition */
3448}
3449
3450/**
3451 * xmlXPathFloorFunction:
3452 * @ctxt: the XPath Parser context
3453 *
3454 * Implement the floor() XPath function
3455 * The floor function returns the largest (closest to positive infinity)
3456 * number that is not greater than the argument and that is an integer.
3457 */
3458void
3459xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3460 CHECK_ARITY(1);
3461 CHECK_TYPE(XPATH_NUMBER);
3462 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003463 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003464}
3465
3466/**
3467 * xmlXPathCeilingFunction:
3468 * @ctxt: the XPath Parser context
3469 *
3470 * Implement the ceiling() XPath function
3471 * The ceiling function returns the smallest (closest to negative infinity)
3472 * number that is not less than the argument and that is an integer.
3473 */
3474void
3475xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003476 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003477
3478 CHECK_ARITY(1);
3479 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003480 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003481 if (f != ctxt->value->floatval)
3482 ctxt->value->floatval = f + 1;
3483}
3484
3485/**
3486 * xmlXPathRoundFunction:
3487 * @ctxt: the XPath Parser context
3488 *
3489 * Implement the round() XPath function
3490 * The round function returns the number that is closest to the
3491 * argument and that is an integer. If there are two such numbers,
3492 * then the one that is even is returned.
3493 */
3494void
3495xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003496 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003497
3498 CHECK_ARITY(1);
3499 CHECK_TYPE(XPATH_NUMBER);
3500 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003501 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003502 if (ctxt->value->floatval < f + 0.5)
3503 ctxt->value->floatval = f;
3504 else if (ctxt->value->floatval == f + 0.5)
3505 ctxt->value->floatval = f; /* !!!! Not following the spec here */
3506 else
3507 ctxt->value->floatval = f + 1;
3508}
3509
3510/************************************************************************
3511 * *
3512 * The Parser *
3513 * *
3514 ************************************************************************/
3515
3516/*
3517 * a couple of forward declarations since we use a recursive call based
3518 * implementation.
3519 */
3520void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3521void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3522void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3523void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3524
3525/**
3526 * xmlXPathParseNCName:
3527 * @ctxt: the XPath Parser context
3528 *
3529 * parse an XML namespace non qualified name.
3530 *
3531 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3532 *
3533 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3534 * CombiningChar | Extender
3535 *
3536 * Returns the namespace name or NULL
3537 */
3538
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003539xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003540xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003541 const xmlChar *q;
3542 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003543
3544 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3545 q = NEXT;
3546
3547 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3548 (CUR == '.') || (CUR == '-') ||
3549 (CUR == '_') ||
3550 (IS_COMBINING(CUR)) ||
3551 (IS_EXTENDER(CUR)))
3552 NEXT;
3553
3554 ret = xmlStrndup(q, CUR_PTR - q);
3555
3556 return(ret);
3557}
3558
3559/**
3560 * xmlXPathParseQName:
3561 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003562 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003563 *
3564 * parse an XML qualified name
3565 *
3566 * [NS 5] QName ::= (Prefix ':')? LocalPart
3567 *
3568 * [NS 6] Prefix ::= NCName
3569 *
3570 * [NS 7] LocalPart ::= NCName
3571 *
3572 * Returns the function returns the local part, and prefix is updated
3573 * to get the Prefix if any.
3574 */
3575
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003576xmlChar *
3577xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3578 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003579
3580 *prefix = NULL;
3581 ret = xmlXPathParseNCName(ctxt);
3582 if (CUR == ':') {
3583 *prefix = ret;
3584 NEXT;
3585 ret = xmlXPathParseNCName(ctxt);
3586 }
3587 return(ret);
3588}
3589
3590/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00003591 * xmlXPathParseName:
3592 * @ctxt: the XPointer Parser context
3593 *
3594 * parse an XML name
3595 *
3596 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3597 * CombiningChar | Extender
3598 *
3599 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3600 *
3601 * Returns the namespace name or NULL
3602 */
3603
3604xmlChar *
3605xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
3606 const xmlChar *q;
3607 xmlChar *ret = NULL;
3608
3609 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3610 q = NEXT;
3611
3612 /* TODO Make this UTF8 compliant !!! */
3613 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3614 (CUR == '.') || (CUR == '-') ||
3615 (CUR == '_') || (CUR == ':') ||
3616 (IS_COMBINING(CUR)) ||
3617 (IS_EXTENDER(CUR)))
3618 NEXT;
3619
3620 ret = xmlStrndup(q, CUR_PTR - q);
3621
3622 return(ret);
3623}
3624
3625/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003626 * xmlXPathStringEvalNumber:
3627 * @str: A string to scan
3628 *
3629 * [30] Number ::= Digits ('.' Digits)?
3630 * | '.' Digits
3631 * [31] Digits ::= [0-9]+
3632 *
3633 * Parse and evaluate a Number in the string
3634 *
3635 * BUG: "1.' is not valid ... James promised correction
3636 * as Digits ('.' Digits?)?
3637 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003638 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003639 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003640double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003641xmlXPathStringEvalNumber(const xmlChar *str) {
3642 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003643 double ret = 0.0;
3644 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003645 int ok = 0;
3646
3647 while (*cur == ' ') cur++;
3648 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003649 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003650 }
3651 while ((*cur >= '0') && (*cur <= '9')) {
3652 ret = ret * 10 + (*cur - '0');
3653 ok = 1;
3654 cur++;
3655 }
3656 if (*cur == '.') {
3657 cur++;
3658 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003659 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003660 }
3661 while ((*cur >= '0') && (*cur <= '9')) {
3662 mult /= 10;
3663 ret = ret + (*cur - '0') * mult;
3664 cur++;
3665 }
3666 }
3667 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003668 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003669 return(ret);
3670}
3671
3672/**
3673 * xmlXPathEvalNumber:
3674 * @ctxt: the XPath Parser context
3675 *
3676 * [30] Number ::= Digits ('.' Digits)?
3677 * | '.' Digits
3678 * [31] Digits ::= [0-9]+
3679 *
3680 * Parse and evaluate a Number, then push it on the stack
3681 *
3682 * BUG: "1.' is not valid ... James promised correction
3683 * as Digits ('.' Digits?)?
3684 */
3685void
3686xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003687 double ret = 0.0;
3688 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003689 int ok = 0;
3690
3691 CHECK_ERROR;
3692 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003693 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003694 }
3695 while ((CUR >= '0') && (CUR <= '9')) {
3696 ret = ret * 10 + (CUR - '0');
3697 ok = 1;
3698 NEXT;
3699 }
3700 if (CUR == '.') {
3701 NEXT;
3702 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003703 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003704 }
3705 while ((CUR >= '0') && (CUR <= '9')) {
3706 mult /= 10;
3707 ret = ret + (CUR - '0') * mult;
3708 NEXT;
3709 }
3710 }
3711 valuePush(ctxt, xmlXPathNewFloat(ret));
3712}
3713
3714/**
3715 * xmlXPathEvalLiteral:
3716 * @ctxt: the XPath Parser context
3717 *
3718 * Parse a Literal and push it on the stack.
3719 *
3720 * [29] Literal ::= '"' [^"]* '"'
3721 * | "'" [^']* "'"
3722 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003723 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003724 */
3725void
3726xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003727 const xmlChar *q;
3728 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003729
3730 if (CUR == '"') {
3731 NEXT;
3732 q = CUR_PTR;
3733 while ((IS_CHAR(CUR)) && (CUR != '"'))
3734 NEXT;
3735 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003736 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003737 } else {
3738 ret = xmlStrndup(q, CUR_PTR - q);
3739 NEXT;
3740 }
3741 } else if (CUR == '\'') {
3742 NEXT;
3743 q = CUR_PTR;
3744 while ((IS_CHAR(CUR)) && (CUR != '\''))
3745 NEXT;
3746 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003747 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003748 } else {
3749 ret = xmlStrndup(q, CUR_PTR - q);
3750 NEXT;
3751 }
3752 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003753 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003754 }
3755 if (ret == NULL) return;
3756 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003757 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003758}
3759
3760/**
3761 * xmlXPathEvalVariableReference:
3762 * @ctxt: the XPath Parser context
3763 *
3764 * Parse a VariableReference, evaluate it and push it on the stack.
3765 *
3766 * The variable bindings consist of a mapping from variable names
3767 * to variable values. The value of a variable is an object, which
3768 * of any of the types that are possible for the value of an expression,
3769 * and may also be of additional types not specified here.
3770 *
3771 * Early evaluation is possible since:
3772 * The variable bindings [...] used to evaluate a subexpression are
3773 * always the same as those used to evaluate the containing expression.
3774 *
3775 * [36] VariableReference ::= '$' QName
3776 */
3777void
3778xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003779 xmlChar *name;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003780 xmlXPathObjectPtr value;
3781
Daniel Veillard55b91f22000-10-05 16:30:11 +00003782 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003783 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003784 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003785 }
Daniel Veillard2d38f042000-10-11 10:54:10 +00003786 name = xmlXPathParseName(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003787 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003788 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003789 }
Daniel Veillard2d38f042000-10-11 10:54:10 +00003790 value = xmlXPathVariableLookup(ctxt->context, name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003791 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003792 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003793 }
3794 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003795 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00003796 SKIP_BLANKS;
3797}
3798
3799/**
3800 * xmlXPathIsNodeType:
3801 * @ctxt: the XPath Parser context
3802 * @name: a name string
3803 *
3804 * Is the name given a NodeType one.
3805 *
3806 * [38] NodeType ::= 'comment'
3807 * | 'text'
3808 * | 'processing-instruction'
3809 * | 'node'
3810 *
3811 * Returns 1 if true 0 otherwise
3812 */
3813int
3814xmlXPathIsNodeType(const xmlChar *name) {
3815 if (name == NULL)
3816 return(0);
3817
3818 if (xmlStrEqual(name, BAD_CAST "comment"))
3819 return(1);
3820 if (xmlStrEqual(name, BAD_CAST "text"))
3821 return(1);
3822 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
3823 return(1);
3824 if (xmlStrEqual(name, BAD_CAST "node"))
3825 return(1);
3826 return(0);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003827}
3828
3829
3830/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00003831 * xmlXPathIsFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003832 * @ctxt: the XPath Parser context
3833 * @name: a name string
3834 *
3835 * Search for a function of the given name
3836 *
3837 * [35] FunctionName ::= QName - NodeType
3838 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003839 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003840 *
3841 * Returns the xmlXPathFunction if found, or NULL otherwise
3842 */
3843xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003844xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00003845 if (name == NULL)
3846 return(NULL);
3847
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003848 switch (name[0]) {
3849 case 'b':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003850 if (xmlStrEqual(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003851 return(xmlXPathBooleanFunction);
3852 break;
3853 case 'c':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003854 if (xmlStrEqual(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003855 return(xmlXPathCeilingFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003856 if (xmlStrEqual(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003857 return(xmlXPathCountFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003858 if (xmlStrEqual(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003859 return(xmlXPathConcatFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003860 if (xmlStrEqual(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003861 return(xmlXPathContainsFunction);
3862 break;
3863 case 'i':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003864 if (xmlStrEqual(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003865 return(xmlXPathIdFunction);
3866 break;
3867 case 'f':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003868 if (xmlStrEqual(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003869 return(xmlXPathFalseFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003870 if (xmlStrEqual(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003871 return(xmlXPathFloorFunction);
3872 break;
3873 case 'l':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003874 if (xmlStrEqual(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003875 return(xmlXPathLastFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003876 if (xmlStrEqual(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003877 return(xmlXPathLangFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003878 if (xmlStrEqual(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003879 return(xmlXPathLocalPartFunction);
3880 break;
3881 case 'n':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003882 if (xmlStrEqual(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003883 return(xmlXPathNotFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003884 if (xmlStrEqual(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003885 return(xmlXPathNameFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003886 if (xmlStrEqual(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003887 return(xmlXPathNamespaceFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003888 if (xmlStrEqual(name, BAD_CAST "normalize-space"))
Daniel Veillard00fdf371999-10-08 09:40:39 +00003889 return(xmlXPathNormalizeFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003890 if (xmlStrEqual(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003891 return(xmlXPathNormalizeFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003892 if (xmlStrEqual(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003893 return(xmlXPathNumberFunction);
3894 break;
3895 case 'p':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003896 if (xmlStrEqual(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003897 return(xmlXPathPositionFunction);
3898 break;
3899 case 'r':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003900 if (xmlStrEqual(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003901 return(xmlXPathRoundFunction);
3902 break;
3903 case 's':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003904 if (xmlStrEqual(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003905 return(xmlXPathStringFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003906 if (xmlStrEqual(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003907 return(xmlXPathStringLengthFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003908 if (xmlStrEqual(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003909 return(xmlXPathStartsWithFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003910 if (xmlStrEqual(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003911 return(xmlXPathSubstringFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003912 if (xmlStrEqual(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003913 return(xmlXPathSubstringBeforeFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003914 if (xmlStrEqual(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003915 return(xmlXPathSubstringAfterFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003916 if (xmlStrEqual(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003917 return(xmlXPathSumFunction);
3918 break;
3919 case 't':
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003920 if (xmlStrEqual(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003921 return(xmlXPathTrueFunction);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003922 if (xmlStrEqual(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003923 return(xmlXPathTranslateFunction);
3924 break;
3925 }
Daniel Veillard2d38f042000-10-11 10:54:10 +00003926 return(xmlXPathFunctionLookup(ctxt->context, name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003927}
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003928
3929/**
3930 * xmlXPathEvalFunctionCall:
3931 * @ctxt: the XPath Parser context
3932 *
3933 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3934 * [17] Argument ::= Expr
3935 *
3936 * Parse and evaluate a function call, the evaluation of all arguments are
3937 * pushed on the stack
3938 */
3939void
3940xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003941 xmlChar *name;
3942 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003943 xmlXPathFunction func;
3944 int nbargs = 0;
3945
3946 name = xmlXPathParseQName(ctxt, &prefix);
3947 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003948 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003949 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003950 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003951 func = xmlXPathIsFunction(ctxt, name);
3952 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003953 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003954 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003955 }
3956#ifdef DEBUG_EXPR
3957 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3958#endif
3959
3960 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003961 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003962 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003963 }
3964 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003965 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003966
3967 while (CUR != ')') {
3968 xmlXPathEvalExpr(ctxt);
3969 nbargs++;
3970 if (CUR == ')') break;
3971 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003972 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003973 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003974 }
3975 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003976 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003977 }
3978 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003979 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003980 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003981 func(ctxt, nbargs);
3982}
3983
3984/**
3985 * xmlXPathEvalPrimaryExpr:
3986 * @ctxt: the XPath Parser context
3987 *
3988 * [15] PrimaryExpr ::= VariableReference
3989 * | '(' Expr ')'
3990 * | Literal
3991 * | Number
3992 * | FunctionCall
3993 *
3994 * Parse and evaluate a primary expression, then push the result on the stack
3995 */
3996void
3997xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003998 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003999 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4000 else if (CUR == '(') {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004001 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004002 SKIP_BLANKS;
Daniel Veillard55b91f22000-10-05 16:30:11 +00004003 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004004 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004005 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004006 }
4007 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004008 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004009 } else if (IS_DIGIT(CUR)) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004010 xmlXPathEvalNumber(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004011 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004012 xmlXPathEvalLiteral(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004013 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004014 xmlXPathEvalFunctionCall(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004015 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004016 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004017}
4018
4019/**
4020 * xmlXPathEvalFilterExpr:
4021 * @ctxt: the XPath Parser context
4022 *
4023 * [20] FilterExpr ::= PrimaryExpr
4024 * | FilterExpr Predicate
4025 *
4026 * Parse and evaluate a filter expression, then push the result on the stack
4027 * Square brackets are used to filter expressions in the same way that
4028 * they are used in location paths. It is an error if the expression to
4029 * be filtered does not evaluate to a node-set. The context node list
4030 * used for evaluating the expression in square brackets is the node-set
4031 * to be filtered listed in document order.
4032 */
4033
4034void
4035xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004036 xmlXPathEvalPrimaryExpr(ctxt);
4037 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004038 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004039
4040 if (CUR != '[') return;
4041
4042 CHECK_TYPE(XPATH_NODESET);
4043
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004044 while (CUR == '[') {
4045 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004046 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004047 }
4048
4049
4050}
4051
4052/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00004053 * xmlXPathScanName:
4054 * @ctxt: the XPath Parser context
4055 *
4056 * Trickery: parse an XML name but without consuming the input flow
Daniel Veillard55b91f22000-10-05 16:30:11 +00004057 * Needed to avoid insanity in the parser state.
Daniel Veillardb96e6431999-08-29 21:02:19 +00004058 *
4059 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4060 * CombiningChar | Extender
4061 *
4062 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4063 *
4064 * [6] Names ::= Name (S Name)*
4065 *
4066 * Returns the Name parsed or NULL
4067 */
4068
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004069xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004070xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004071 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00004072 int len = 0;
4073
Daniel Veillard00fdf371999-10-08 09:40:39 +00004074 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004075 if (!IS_LETTER(CUR) && (CUR != '_') &&
4076 (CUR != ':')) {
4077 return(NULL);
4078 }
4079
4080 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4081 (NXT(len) == '.') || (NXT(len) == '-') ||
4082 (NXT(len) == '_') || (NXT(len) == ':') ||
4083 (IS_COMBINING(NXT(len))) ||
4084 (IS_EXTENDER(NXT(len)))) {
4085 buf[len] = NXT(len);
4086 len++;
4087 if (len >= XML_MAX_NAMELEN) {
4088 fprintf(stderr,
4089 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
4090 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4091 (NXT(len) == '.') || (NXT(len) == '-') ||
4092 (NXT(len) == '_') || (NXT(len) == ':') ||
4093 (IS_COMBINING(NXT(len))) ||
4094 (IS_EXTENDER(NXT(len))))
4095 len++;
4096 break;
4097 }
4098 }
4099 return(xmlStrndup(buf, len));
4100}
4101
4102/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004103 * xmlXPathEvalPathExpr:
4104 * @ctxt: the XPath Parser context
4105 *
4106 * [19] PathExpr ::= LocationPath
4107 * | FilterExpr
4108 * | FilterExpr '/' RelativeLocationPath
4109 * | FilterExpr '//' RelativeLocationPath
4110 *
4111 * Parse and evaluate a path expression, then push the result on the stack
4112 * The / operator and // operators combine an arbitrary expression
4113 * and a relative location path. It is an error if the expression
4114 * does not evaluate to a node-set.
4115 * The / operator does composition in the same way as when / is
4116 * used in a location path. As in location paths, // is short for
4117 * /descendant-or-self::node()/.
4118 */
4119
4120void
4121xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004122 int lc = 1; /* Should we branch to LocationPath ? */
4123 xmlChar *name = NULL; /* we may have to preparse a name to find out */
4124
Daniel Veillard00fdf371999-10-08 09:40:39 +00004125 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004126 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
4127 (CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004128 lc = 0;
4129 } else if (CUR == '/') {
4130 /* relative or absolute location path */
4131 lc = 1;
4132 } else if (CUR == '@') {
4133 /* relative abbreviated attribute location path */
4134 lc = 1;
4135 } else if (CUR == '.') {
4136 /* relative abbreviated attribute location path */
4137 lc = 1;
4138 } else {
4139 /*
4140 * Problem is finding if we have a name here whether it's:
4141 * - a nodetype
4142 * - a function call in which case it's followed by '('
4143 * - an axis in which case it's followed by ':'
4144 * - a element name
4145 * We do an a priori analysis here rather than having to
4146 * maintain parsed token content through the recursive function
4147 * calls. This looks uglier but makes the code quite easier to
4148 * read/write/debug.
4149 */
4150 SKIP_BLANKS;
4151 name = xmlXPathScanName(ctxt);
4152 if (name != NULL) {
4153 int len =xmlStrlen(name);
4154 int blank = 0;
4155
4156 while (NXT(len) != 0) {
4157 if (NXT(len) == '/') {
4158 /* element name */
4159#ifdef DEBUG_STEP
4160 fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4161#endif
4162 lc = 1;
4163 break;
4164 } else if (IS_BLANK(NXT(len))) {
4165 /* skip to next */
4166 blank = 1;
4167 } else if (NXT(len) == ':') {
4168#ifdef DEBUG_STEP
4169 fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4170#endif
4171 lc = 1;
4172 break;
4173 } else if ((NXT(len) == '(')) {
4174 /* Note Type or Function */
4175 if (xmlXPathIsNodeType(name)) {
4176#ifdef DEBUG_STEP
4177 fprintf(xmlXPathDebug, "PathExpr: Type search\n");
4178#endif
4179 lc = 1;
4180 } else {
4181#ifdef DEBUG_STEP
4182 fprintf(xmlXPathDebug, "PathExpr: function call\n");
4183#endif
4184 lc = 0;
4185 }
4186 break;
4187 } else if ((NXT(len) == '[')) {
4188 /* element name */
4189#ifdef DEBUG_STEP
4190 fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4191#endif
4192 lc = 1;
4193 break;
4194 } else {
4195 XP_ERROR(XPATH_EXPR_ERROR);
4196 }
4197 len++;
4198 }
4199 if (NXT(len) == 0) {
4200#ifdef DEBUG_STEP
4201 fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4202#endif
4203 /* element name */
4204 lc = 1;
4205 }
4206 xmlFree(name);
4207 } else {
4208 /* make sure all cases are covered explicitely */
4209 XP_ERROR(XPATH_EXPR_ERROR);
4210 }
4211 }
4212
4213 if (lc) {
4214 xmlXPathEvalLocationPath(ctxt);
4215 } else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004216 xmlXPathEvalFilterExpr(ctxt);
4217 CHECK_ERROR;
4218 if ((CUR == '/') && (NXT(1) == '/')) {
4219 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004220 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00004221 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004222 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004223 ctxt->context->node = NULL;
4224 xmlXPathEvalRelativeLocationPath(ctxt);
4225 } else if (CUR == '/') {
4226 xmlXPathEvalRelativeLocationPath(ctxt);
4227 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004228 }
4229 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004230}
4231
4232/**
4233 * xmlXPathEvalUnionExpr:
4234 * @ctxt: the XPath Parser context
4235 *
4236 * [18] UnionExpr ::= PathExpr
4237 * | UnionExpr '|' PathExpr
4238 *
4239 * Parse and evaluate an union expression, then push the result on the stack
4240 */
4241
4242void
4243xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
4244 xmlXPathEvalPathExpr(ctxt);
4245 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004246 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004247 if (CUR == '|') {
Daniel Veillard740abf52000-10-02 23:04:54 +00004248 xmlXPathObjectPtr obj1,obj2;
4249
4250 CHECK_TYPE(XPATH_NODESET);
4251 obj1 = valuePop(ctxt);
4252 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004253
Daniel Veillard00fdf371999-10-08 09:40:39 +00004254 NEXT;
4255 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004256 xmlXPathEvalPathExpr(ctxt);
4257
Daniel Veillard740abf52000-10-02 23:04:54 +00004258 CHECK_TYPE(XPATH_NODESET);
4259 obj2 = valuePop(ctxt);
4260 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
4261 obj2->nodesetval);
4262 xmlXPathFreeObject(obj2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004263 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004264 }
4265}
4266
4267/**
4268 * xmlXPathEvalUnaryExpr:
4269 * @ctxt: the XPath Parser context
4270 *
4271 * [27] UnaryExpr ::= UnionExpr
4272 * | '-' UnaryExpr
4273 *
4274 * Parse and evaluate an unary expression, then push the result on the stack
4275 */
4276
4277void
4278xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
4279 int minus = 0;
4280
Daniel Veillard00fdf371999-10-08 09:40:39 +00004281 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004282 if (CUR == '-') {
4283 minus = 1;
4284 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004285 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004286 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004287 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004288 CHECK_ERROR;
4289 if (minus) {
4290 xmlXPathValueFlipSign(ctxt);
4291 }
4292}
4293
4294/**
4295 * xmlXPathEvalMultiplicativeExpr:
4296 * @ctxt: the XPath Parser context
4297 *
4298 * [26] MultiplicativeExpr ::= UnaryExpr
4299 * | MultiplicativeExpr MultiplyOperator UnaryExpr
4300 * | MultiplicativeExpr 'div' UnaryExpr
4301 * | MultiplicativeExpr 'mod' UnaryExpr
4302 * [34] MultiplyOperator ::= '*'
4303 *
4304 * Parse and evaluate an Additive expression, then push the result on the stack
4305 */
4306
4307void
4308xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
4309 xmlXPathEvalUnaryExpr(ctxt);
4310 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004311 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004312 while ((CUR == '*') ||
4313 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
4314 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
4315 int op = -1;
4316
4317 if (CUR == '*') {
4318 op = 0;
4319 NEXT;
4320 } else if (CUR == 'd') {
4321 op = 1;
4322 SKIP(3);
4323 } else if (CUR == 'm') {
4324 op = 2;
4325 SKIP(3);
4326 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004327 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004328 xmlXPathEvalUnaryExpr(ctxt);
4329 CHECK_ERROR;
4330 switch (op) {
4331 case 0:
4332 xmlXPathMultValues(ctxt);
4333 break;
4334 case 1:
4335 xmlXPathDivValues(ctxt);
4336 break;
4337 case 2:
4338 xmlXPathModValues(ctxt);
4339 break;
4340 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004341 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004342 }
4343}
4344
4345/**
4346 * xmlXPathEvalAdditiveExpr:
4347 * @ctxt: the XPath Parser context
4348 *
4349 * [25] AdditiveExpr ::= MultiplicativeExpr
4350 * | AdditiveExpr '+' MultiplicativeExpr
4351 * | AdditiveExpr '-' MultiplicativeExpr
4352 *
4353 * Parse and evaluate an Additive expression, then push the result on the stack
4354 */
4355
4356void
4357xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
4358 xmlXPathEvalMultiplicativeExpr(ctxt);
4359 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004360 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004361 while ((CUR == '+') || (CUR == '-')) {
4362 int plus;
4363
4364 if (CUR == '+') plus = 1;
4365 else plus = 0;
4366 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004367 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004368 xmlXPathEvalMultiplicativeExpr(ctxt);
4369 CHECK_ERROR;
4370 if (plus) xmlXPathAddValues(ctxt);
4371 else xmlXPathSubValues(ctxt);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004372 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004373 }
4374}
4375
4376/**
4377 * xmlXPathEvalRelationalExpr:
4378 * @ctxt: the XPath Parser context
4379 *
4380 * [24] RelationalExpr ::= AdditiveExpr
4381 * | RelationalExpr '<' AdditiveExpr
4382 * | RelationalExpr '>' AdditiveExpr
4383 * | RelationalExpr '<=' AdditiveExpr
4384 * | RelationalExpr '>=' AdditiveExpr
4385 *
4386 * A <= B > C is allowed ? Answer from James, yes with
4387 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
4388 * which is basically what got implemented.
4389 *
4390 * Parse and evaluate a Relational expression, then push the result
4391 * on the stack
4392 */
4393
4394void
4395xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
4396 xmlXPathEvalAdditiveExpr(ctxt);
4397 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004398 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004399 while ((CUR == '<') ||
4400 (CUR == '>') ||
4401 ((CUR == '<') && (NXT(1) == '=')) ||
4402 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004403 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004404
4405 if (CUR == '<') inf = 1;
4406 else inf = 0;
4407 if (NXT(1) == '=') strict = 0;
4408 else strict = 1;
4409 NEXT;
4410 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004411 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004412 xmlXPathEvalAdditiveExpr(ctxt);
4413 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004414 ret = xmlXPathCompareValues(ctxt, inf, strict);
4415 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard55b91f22000-10-05 16:30:11 +00004416 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004417 }
4418}
4419
4420/**
4421 * xmlXPathEvalEqualityExpr:
4422 * @ctxt: the XPath Parser context
4423 *
4424 * [23] EqualityExpr ::= RelationalExpr
4425 * | EqualityExpr '=' RelationalExpr
4426 * | EqualityExpr '!=' RelationalExpr
4427 *
4428 * A != B != C is allowed ? Answer from James, yes with
4429 * (RelationalExpr = RelationalExpr) = RelationalExpr
4430 * (RelationalExpr != RelationalExpr) != RelationalExpr
4431 * which is basically what got implemented.
4432 *
4433 * Parse and evaluate an Equality expression, then push the result on the stack
4434 *
4435 */
4436void
4437xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
4438 xmlXPathEvalRelationalExpr(ctxt);
4439 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004440 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004441 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004442 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004443 int eq, equal;
4444
4445 if (CUR == '=') eq = 1;
4446 else eq = 0;
4447 NEXT;
4448 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004449 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004450 xmlXPathEvalRelationalExpr(ctxt);
4451 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004452 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004453 if (eq) res = xmlXPathNewBoolean(equal);
4454 else res = xmlXPathNewBoolean(!equal);
4455 valuePush(ctxt, res);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004456 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004457 }
4458}
4459
4460/**
4461 * xmlXPathEvalAndExpr:
4462 * @ctxt: the XPath Parser context
4463 *
4464 * [22] AndExpr ::= EqualityExpr
4465 * | AndExpr 'and' EqualityExpr
4466 *
4467 * Parse and evaluate an AND expression, then push the result on the stack
4468 *
4469 */
4470void
4471xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
4472 xmlXPathEvalEqualityExpr(ctxt);
4473 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004474 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00004475 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004476 xmlXPathObjectPtr arg1, arg2;
4477
4478 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004479 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004480 xmlXPathEvalEqualityExpr(ctxt);
4481 CHECK_ERROR;
4482 arg2 = valuePop(ctxt);
4483 arg1 = valuePop(ctxt);
4484 arg1->boolval &= arg2->boolval;
4485 valuePush(ctxt, arg1);
4486 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004487 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004488 }
4489}
4490
4491/**
4492 * xmlXPathEvalExpr:
4493 * @ctxt: the XPath Parser context
4494 *
4495 * [14] Expr ::= OrExpr
4496 * [21] OrExpr ::= AndExpr
4497 * | OrExpr 'or' AndExpr
4498 *
4499 * Parse and evaluate an expression, then push the result on the stack
4500 *
4501 */
4502void
4503xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
4504 xmlXPathEvalAndExpr(ctxt);
4505 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004506 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004507 while ((CUR == 'o') && (NXT(1) == 'r')) {
4508 xmlXPathObjectPtr arg1, arg2;
4509
4510 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004511 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004512 xmlXPathEvalAndExpr(ctxt);
4513 CHECK_ERROR;
4514 arg2 = valuePop(ctxt);
4515 arg1 = valuePop(ctxt);
4516 arg1->boolval |= arg2->boolval;
4517 valuePush(ctxt, arg1);
4518 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004519 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004520 }
4521}
4522
4523/**
4524 * xmlXPathEvaluatePredicateResult:
4525 * @ctxt: the XPath Parser context
4526 * @res: the Predicate Expression evaluation result
4527 * @index: index of the current node in the current list
4528 *
4529 * Evaluate a predicate result for the current node.
4530 * A PredicateExpr is evaluated by evaluating the Expr and converting
4531 * the result to a boolean. If the result is a number, the result will
4532 * be converted to true if the number is equal to the position of the
4533 * context node in the context node list (as returned by the position
4534 * function) and will be converted to false otherwise; if the result
4535 * is not a number, then the result will be converted as if by a call
4536 * to the boolean function.
4537 */
4538int
4539xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004540 xmlXPathObjectPtr res) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004541 if (res == NULL) return(0);
4542 switch (res->type) {
4543 case XPATH_BOOLEAN:
4544 return(res->boolval);
4545 case XPATH_NUMBER:
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004546 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004547 case XPATH_NODESET:
4548 return(res->nodesetval->nodeNr != 0);
4549 case XPATH_STRING:
4550 return((res->stringval != NULL) &&
4551 (xmlStrlen(res->stringval) != 0));
4552 default:
4553 STRANGE
4554 }
4555 return(0);
4556}
4557
4558/**
4559 * xmlXPathEvalPredicate:
4560 * @ctxt: the XPath Parser context
4561 *
4562 * [8] Predicate ::= '[' PredicateExpr ']'
4563 * [9] PredicateExpr ::= Expr
4564 *
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004565 * ---------------------
4566 * For each node in the node-set to be filtered, the PredicateExpr is
4567 * evaluated with that node as the context node, with the number of nodes
4568 * in the node-set as the context size, and with the proximity position
4569 * of the node in the node-set with respect to the axis as the context
4570 * position; if PredicateExpr evaluates to true for that node, the node
4571 * is included in the new node-set; otherwise, it is not included.
4572 * ---------------------
4573 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004574 * Parse and evaluate a predicate for all the elements of the
4575 * current node list. Then refine the list by removing all
4576 * nodes where the predicate is false.
4577 */
4578void
4579xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004580 const xmlChar *cur;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004581 xmlXPathObjectPtr res;
Daniel Veillard740abf52000-10-02 23:04:54 +00004582 xmlXPathObjectPtr obj, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004583 xmlNodeSetPtr newset = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004584 xmlNodeSetPtr oldset;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004585 int i;
4586
Daniel Veillard00fdf371999-10-08 09:40:39 +00004587 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004588 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004589 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004590 }
4591 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004592 SKIP_BLANKS;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004593
4594 /*
4595 * Extract the old set, and then evaluate the result of the
4596 * expression for all the element in the set. use it to grow
4597 * up a new set.
4598 */
Daniel Veillard740abf52000-10-02 23:04:54 +00004599 CHECK_TYPE(XPATH_NODESET);
4600 obj = valuePop(ctxt);
4601 oldset = obj->nodesetval;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004602 ctxt->context->node = NULL;
4603
4604 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004605 xmlXPathEvalExpr(ctxt);
4606 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004607 ctxt->context->contextSize = 0;
4608 ctxt->context->proximityPosition = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004609 res = valuePop(ctxt);
4610 if (res != NULL)
4611 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00004612 valuePush(ctxt, obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004613 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004614 /*
4615 * Save the expression pointer since we will have to evaluate
4616 * it multiple times. Initialize the new set.
4617 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004618 cur = ctxt->cur;
4619 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00004620
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004621 for (i = 0; i < oldset->nodeNr; i++) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004622 ctxt->cur = cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00004623
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004624 /*
4625 * Run the evaluation with a node list made of a single item
4626 * in the nodeset.
4627 */
4628 ctxt->context->node = oldset->nodeTab[i];
Daniel Veillard740abf52000-10-02 23:04:54 +00004629 tmp = xmlXPathNewNodeSet(ctxt->context->node);
4630 valuePush(ctxt, tmp);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004631 ctxt->context->contextSize = oldset->nodeNr;
4632 ctxt->context->proximityPosition = i + 1;
Daniel Veillardbe803962000-06-28 23:40:59 +00004633
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004634 xmlXPathEvalExpr(ctxt);
4635 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004636
4637 /*
4638 * The result of the evaluation need to be tested to
4639 * decided whether the filter succeeded or not
4640 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004641 res = valuePop(ctxt);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004642 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
4643 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
4644 }
Daniel Veillard740abf52000-10-02 23:04:54 +00004645
4646 /*
4647 * Cleanup
4648 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004649 if (res != NULL)
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004650 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00004651 if (ctxt->value == tmp) {
4652 res = valuePop(ctxt);
4653 xmlXPathFreeObject(res);
4654 }
Daniel Veillardbe803962000-06-28 23:40:59 +00004655
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004656 ctxt->context->node = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004657 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004658
4659 /*
4660 * The result is used as the new evaluation set.
4661 */
Daniel Veillard740abf52000-10-02 23:04:54 +00004662 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004663 ctxt->context->node = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004664 ctxt->context->contextSize = -1;
4665 ctxt->context->proximityPosition = -1;
Daniel Veillard740abf52000-10-02 23:04:54 +00004666 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004667 }
4668 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004669 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004670 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004671
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004672 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004673 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004674#ifdef DEBUG_STEP
4675 fprintf(xmlXPathDebug, "After predicate : ");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004676 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004677#endif
4678}
4679
4680/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00004681 * xmlXPathEvalNodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004682 * @ctxt: the XPath Parser context
Daniel Veillard55b91f22000-10-05 16:30:11 +00004683 * @test: pointer to a xmlXPathTestVal
4684 * @type: pointer to a xmlXPathTypeVal
4685 * @prefix: placeholder for a possible name prefix
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004686 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00004687 * [7] NodeTest ::= NameTest
4688 * | NodeType '(' ')'
4689 * | 'processing-instruction' '(' Literal ')'
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004690 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00004691 * [37] NameTest ::= '*'
4692 * | NCName ':' '*'
4693 * | QName
4694 * [38] NodeType ::= 'comment'
4695 * | 'text'
4696 * | 'processing-instruction'
4697 * | 'node'
4698 *
4699 * Returns the name found and update @test, @type and @prefix appropriately
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004700 */
Daniel Veillard55b91f22000-10-05 16:30:11 +00004701xmlChar *
4702xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
4703 xmlXPathTypeVal *type, xmlChar **prefix, xmlChar *name) {
4704 int blanks;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004705
Daniel Veillard55b91f22000-10-05 16:30:11 +00004706 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
4707 STRANGE;
4708 return(NULL);
4709 }
4710 *type = 0;
4711 *test = 0;
4712 *prefix = NULL;
4713 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004714
Daniel Veillard55b91f22000-10-05 16:30:11 +00004715 if ((name == NULL) && (CUR == '*')) {
4716 /*
4717 * All elements
4718 */
4719 NEXT;
4720 *test = NODE_TEST_ALL;
4721 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004722 }
4723
Daniel Veillard55b91f22000-10-05 16:30:11 +00004724 if (name == NULL)
4725 name = xmlXPathParseNCName(ctxt);
4726 if (name == NULL) {
4727 XP_ERROR0(XPATH_EXPR_ERROR);
4728 }
4729
4730 blanks = IS_BLANK(CUR);
4731 SKIP_BLANKS;
4732 if (CUR == '(') {
4733 NEXT;
4734 /*
4735 * NodeType or PI search
4736 */
4737 if (xmlStrEqual(name, BAD_CAST "comment"))
4738 *type = NODE_TYPE_COMMENT;
4739 else if (xmlStrEqual(name, BAD_CAST "node"))
4740 *type = NODE_TYPE_NODE;
4741 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4742 *type = NODE_TYPE_PI;
4743 else if (xmlStrEqual(name, BAD_CAST "text"))
4744 *type = NODE_TYPE_TEXT;
4745 else
4746 XP_ERROR0(XPATH_EXPR_ERROR);
4747
4748 *test = NODE_TEST_TYPE;
4749
4750 SKIP_BLANKS;
4751 if (*type == NODE_TYPE_PI) {
4752 /*
4753 * Specific case: search a PI by name.
4754 */
4755 xmlXPathObjectPtr cur;
4756
4757 if (name != NULL)
4758 xmlFree(name);
4759
4760 xmlXPathEvalLiteral(ctxt);
4761 CHECK_ERROR 0;
4762 xmlXPathStringFunction(ctxt, 1);
4763 CHECK_ERROR0;
4764 cur = valuePop(ctxt);
4765 name = xmlStrdup(cur->stringval);
4766 xmlXPathFreeObject(cur);
4767 SKIP_BLANKS;
4768 }
4769 if (CUR != ')')
4770 XP_ERROR0(XPATH_UNCLOSED_ERROR);
4771 NEXT;
4772 return(name);
4773 }
4774 *test = NODE_TEST_NAME;
4775 if ((!blanks) && (CUR == ':')) {
4776 NEXT;
4777
4778 *prefix = name;
4779
4780 if (CUR == '*') {
4781 /*
4782 * All elements
4783 */
4784 NEXT;
4785 *test = NODE_TEST_ALL;
4786 return(NULL);
4787 }
4788
4789 name = xmlXPathParseNCName(ctxt);
4790 if (name == NULL) {
4791 XP_ERROR0(XPATH_EXPR_ERROR);
4792 }
4793 }
4794 return(name);
4795}
4796
4797/**
4798 * xmlXPathIsAxisName:
4799 * @name: a preparsed name token
4800 *
4801 * [6] AxisName ::= 'ancestor'
4802 * | 'ancestor-or-self'
4803 * | 'attribute'
4804 * | 'child'
4805 * | 'descendant'
4806 * | 'descendant-or-self'
4807 * | 'following'
4808 * | 'following-sibling'
4809 * | 'namespace'
4810 * | 'parent'
4811 * | 'preceding'
4812 * | 'preceding-sibling'
4813 * | 'self'
4814 *
4815 * Returns the axis or 0
4816 */
4817xmlXPathAxisVal
4818xmlXPathIsAxisName(const xmlChar *name) {
4819 xmlXPathAxisVal ret = 0;
4820 switch (name[0]) {
4821 case 'a':
4822 if (xmlStrEqual(name, BAD_CAST "ancestor"))
4823 ret = AXIS_ANCESTOR;
4824 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
4825 ret = AXIS_ANCESTOR_OR_SELF;
4826 if (xmlStrEqual(name, BAD_CAST "attribute"))
4827 ret = AXIS_ATTRIBUTE;
4828 break;
4829 case 'c':
4830 if (xmlStrEqual(name, BAD_CAST "child"))
4831 ret = AXIS_CHILD;
4832 break;
4833 case 'd':
4834 if (xmlStrEqual(name, BAD_CAST "descendant"))
4835 ret = AXIS_DESCENDANT;
4836 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
4837 ret = AXIS_DESCENDANT_OR_SELF;
4838 break;
4839 case 'f':
4840 if (xmlStrEqual(name, BAD_CAST "following"))
4841 ret = AXIS_FOLLOWING;
4842 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
4843 ret = AXIS_FOLLOWING_SIBLING;
4844 break;
4845 case 'n':
4846 if (xmlStrEqual(name, BAD_CAST "namespace"))
4847 ret = AXIS_NAMESPACE;
4848 break;
4849 case 'p':
4850 if (xmlStrEqual(name, BAD_CAST "parent"))
4851 ret = AXIS_PARENT;
4852 if (xmlStrEqual(name, BAD_CAST "preceding"))
4853 ret = AXIS_PRECEDING;
4854 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
4855 ret = AXIS_PRECEDING_SIBLING;
4856 break;
4857 case 's':
4858 if (xmlStrEqual(name, BAD_CAST "self"))
4859 ret = AXIS_SELF;
4860 break;
4861 }
4862 return(ret);
4863}
4864
4865/**
4866 * xmlXPathEvalAxisSpecifier:
4867 * @ctxt: the XPath Parser context
4868 *
4869 *
4870 * Returns the axis found
4871 */
4872xmlXPathAxisVal
4873xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
4874 xmlXPathAxisVal ret = AXIS_CHILD;
4875 int blank = 0;
4876 xmlChar *name;
4877
4878 if (CUR == '@') {
4879 NEXT;
4880 return(AXIS_ATTRIBUTE);
4881 } else {
4882 name = xmlXPathParseNCName(ctxt);
4883 if (name == NULL) {
4884 XP_ERROR0(XPATH_EXPR_ERROR);
4885 }
4886 if (IS_BLANK(CUR))
4887 blank = 1;
4888 SKIP_BLANKS;
4889 if ((CUR == ':') && (NXT(1) == ':')) {
4890 ret = xmlXPathIsAxisName(name);
4891 } else if ((blank) && (CUR == ':'))
4892 XP_ERROR0(XPATH_EXPR_ERROR);
4893
4894 xmlFree(name);
4895 }
4896 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004897}
4898
4899/**
4900 * xmlXPathEvalStep:
4901 * @ctxt: the XPath Parser context
4902 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00004903 * [4] Step ::= AxisSpecifier NodeTest Predicate*
4904 * | AbbreviatedStep
Daniel Veillardac260302000-10-04 13:33:43 +00004905 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00004906 * [12] AbbreviatedStep ::= '.' | '..'
4907 *
4908 * [5] AxisSpecifier ::= AxisName '::'
4909 * | AbbreviatedAxisSpecifier
4910 *
4911 * [13] AbbreviatedAxisSpecifier ::= '@'?
Daniel Veillardac260302000-10-04 13:33:43 +00004912 *
4913 * Modified for XPtr range support as:
4914 *
4915 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
4916 * | AbbreviatedStep
4917 * | 'range-to' '(' Expr ')' Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004918 *
4919 * Evaluate one step in a Location Path
4920 * A location step of . is short for self::node(). This is
4921 * particularly useful in conjunction with //. For example, the
4922 * location path .//para is short for
4923 * self::node()/descendant-or-self::node()/child::para
4924 * and so will select all para descendant elements of the context
4925 * node.
4926 * Similarly, a location step of .. is short for parent::node().
4927 * For example, ../title is short for parent::node()/child::title
4928 * and so will select the title children of the parent of the context
4929 * node.
4930 */
4931void
4932xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004933 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004934 if ((CUR == '.') && (NXT(1) == '.')) {
4935 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004936 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00004937 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004938 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004939 } else if (CUR == '.') {
4940 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004941 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004942 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004943 xmlChar *name = NULL;
4944 xmlChar *prefix = NULL;
4945 xmlXPathTestVal test;
4946 xmlXPathAxisVal axis;
4947 xmlXPathTypeVal type;
4948
4949 /*
4950 * The modification needed for XPointer change to the production
4951 */
Daniel Veillardac260302000-10-04 13:33:43 +00004952#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard55b91f22000-10-05 16:30:11 +00004953 if (ctxt->context->xptr) {
4954 name = xmlXPathParseNCName(ctxt);
4955 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
4956 xmlFree(name);
4957 SKIP_BLANKS;
4958 if (CUR != '(') {
4959 XP_ERROR(XPATH_EXPR_ERROR);
4960 }
4961 NEXT;
4962 SKIP_BLANKS;
Daniel Veillardac260302000-10-04 13:33:43 +00004963
Daniel Veillard55b91f22000-10-05 16:30:11 +00004964 xmlXPtrRangeToFunction(ctxt, 1);
Daniel Veillardac260302000-10-04 13:33:43 +00004965 CHECK_ERROR;
4966
Daniel Veillard55b91f22000-10-05 16:30:11 +00004967 SKIP_BLANKS;
4968 if (CUR != ')') {
4969 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardac260302000-10-04 13:33:43 +00004970 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004971 NEXT;
4972 goto eval_predicates;
Daniel Veillardac260302000-10-04 13:33:43 +00004973 }
Daniel Veillardac260302000-10-04 13:33:43 +00004974 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004975#endif
4976 if (name == NULL)
4977 name = xmlXPathParseNCName(ctxt);
4978 if (name != NULL) {
4979 axis = xmlXPathIsAxisName(name);
4980 if (axis != 0) {
4981 SKIP_BLANKS;
4982 if ((CUR == ':') && (NXT(1) == ':')) {
4983 SKIP(2);
4984 xmlFree(name);
4985 name = NULL;
4986 } else {
4987 /* an element name can conflict with an axis one :-\ */
4988 axis = AXIS_CHILD;
4989 }
4990 } else {
4991 axis = AXIS_CHILD;
4992 }
4993 } else if (CUR == '@') {
4994 NEXT;
4995 axis = AXIS_ATTRIBUTE;
4996 } else {
4997 axis = AXIS_CHILD;
4998 }
4999
5000 CHECK_ERROR;
5001
5002 name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
5003 if (test == 0)
5004 return;
5005
5006#ifdef DEBUG_STEP
5007 fprintf(xmlXPathDebug, "Basis : computing new set\n");
5008#endif
5009 xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
5010#ifdef DEBUG_STEP
5011 fprintf(xmlXPathDebug, "Basis : ");
5012 xmlXPathDebugNodeSet(stdout, ctxt->value->nodesetval);
5013#endif
5014 if (name != NULL)
5015 xmlFree(name);
5016 if (prefix != NULL)
5017 xmlFree(prefix);
5018
5019eval_predicates:
Daniel Veillard00fdf371999-10-08 09:40:39 +00005020 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005021 while (CUR == '[') {
5022 xmlXPathEvalPredicate(ctxt);
5023 }
5024 }
5025#ifdef DEBUG_STEP
5026 fprintf(xmlXPathDebug, "Step : ");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005027 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005028#endif
5029}
5030
5031/**
5032 * xmlXPathEvalRelativeLocationPath:
5033 * @ctxt: the XPath Parser context
5034 *
5035 * [3] RelativeLocationPath ::= Step
5036 * | RelativeLocationPath '/' Step
5037 * | AbbreviatedRelativeLocationPath
5038 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
5039 *
5040 */
5041void
5042xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005043 SKIP_BLANKS;
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00005044 if ((CUR == '/') && (NXT(1) == '/')) {
5045 SKIP(2);
5046 SKIP_BLANKS;
5047 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
5048 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
5049 } else if (CUR == '/') {
5050 NEXT;
5051 SKIP_BLANKS;
5052 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005053 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005054 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005055 while (CUR == '/') {
5056 if ((CUR == '/') && (NXT(1) == '/')) {
5057 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005058 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005059 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005060 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005061 xmlXPathEvalStep(ctxt);
5062 } else if (CUR == '/') {
5063 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005064 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005065 xmlXPathEvalStep(ctxt);
5066 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005067 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005068 }
5069}
5070
5071/**
5072 * xmlXPathEvalLocationPath:
5073 * @ctxt: the XPath Parser context
5074 *
5075 * [1] LocationPath ::= RelativeLocationPath
5076 * | AbsoluteLocationPath
5077 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
5078 * | AbbreviatedAbsoluteLocationPath
5079 * [10] AbbreviatedAbsoluteLocationPath ::=
5080 * '//' RelativeLocationPath
5081 *
5082 * // is short for /descendant-or-self::node()/. For example,
5083 * //para is short for /descendant-or-self::node()/child::para and
5084 * so will select any para element in the document (even a para element
5085 * that is a document element will be selected by //para since the
5086 * document element node is a child of the root node); div//para is
5087 * short for div/descendant-or-self::node()/child::para and so will
5088 * select all para descendants of div children.
5089 */
5090void
5091xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005092 SKIP_BLANKS;
5093 if (CUR != '/') {
5094 xmlXPathEvalRelativeLocationPath(ctxt);
5095 } else {
5096 while (CUR == '/') {
5097 if ((CUR == '/') && (NXT(1) == '/')) {
5098 SKIP(2);
5099 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005100 xmlXPathNodeCollectAndTest(ctxt,
Daniel Veillard00fdf371999-10-08 09:40:39 +00005101 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
5102 XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005103 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005104 } else if (CUR == '/') {
5105 NEXT;
5106 SKIP_BLANKS;
5107 xmlXPathRoot(ctxt);
5108 if (CUR != 0)
5109 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005110 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005111 }
5112 }
5113}
5114
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005115/**
5116 * xmlXPathEval:
5117 * @str: the XPath expression
Daniel Veillard740abf52000-10-02 23:04:54 +00005118 * @ctx: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005119 *
5120 * Evaluate the XPath Location Path in the given context.
5121 *
5122 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
5123 * the caller has to free the object.
5124 */
5125xmlXPathObjectPtr
Daniel Veillard740abf52000-10-02 23:04:54 +00005126xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
5127 xmlXPathParserContextPtr ctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005128 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005129 xmlXPathObjectPtr init = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005130 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005131
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005132 xmlXPathInit();
5133
Daniel Veillard740abf52000-10-02 23:04:54 +00005134 CHECK_CONTEXT(ctx)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005135
5136 if (xmlXPathDebug == NULL)
5137 xmlXPathDebug = stderr;
Daniel Veillard740abf52000-10-02 23:04:54 +00005138 ctxt = xmlXPathNewParserContext(str, ctx);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005139 if (ctx->node != NULL) {
5140 init = xmlXPathNewNodeSet(ctx->node);
5141 valuePush(ctxt, init);
5142 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005143 if (str[0] == '/')
Daniel Veillard55b91f22000-10-05 16:30:11 +00005144 xmlXPathRoot(ctxt);
5145 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005146
Daniel Veillard740abf52000-10-02 23:04:54 +00005147 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
5148 fprintf(xmlXPathDebug,
5149 "xmlXPathEval: evaluation failed to return a node set\n");
5150 } else {
5151 res = valuePop(ctxt);
5152 }
5153
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005154 do {
Daniel Veillard740abf52000-10-02 23:04:54 +00005155 tmp = valuePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005156 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00005157 xmlXPathFreeObject(tmp);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005158 if (tmp != init)
5159 stack++;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005160 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005161 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005162 if (stack != 0) {
5163 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
5164 stack);
5165 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005166 if (ctxt->error != XPATH_EXPRESSION_OK) {
5167 xmlXPathFreeObject(res);
5168 res = NULL;
5169 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005170
Daniel Veillard740abf52000-10-02 23:04:54 +00005171 xmlXPathFreeParserContext(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005172 return(res);
5173}
5174
5175/**
5176 * xmlXPathEvalExpression:
5177 * @str: the XPath expression
5178 * @ctxt: the XPath context
5179 *
5180 * Evaluate the XPath expression in the given context.
5181 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00005182 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005183 * the caller has to free the object.
5184 */
5185xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005186xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005187 xmlXPathParserContextPtr pctxt;
5188 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005189 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005190
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005191 xmlXPathInit();
5192
Daniel Veillard740abf52000-10-02 23:04:54 +00005193 CHECK_CONTEXT(ctxt)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005194
5195 if (xmlXPathDebug == NULL)
5196 xmlXPathDebug = stderr;
5197 pctxt = xmlXPathNewParserContext(str, ctxt);
5198 xmlXPathEvalExpr(pctxt);
5199
5200 res = valuePop(pctxt);
5201 do {
5202 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005203 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005204 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005205 stack++;
5206 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005207 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005208 if (stack != 0) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005209 fprintf(xmlXPathDebug, "xmlXPathEvalExpression: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005210 stack);
5211 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005212 xmlXPathFreeParserContext(pctxt);
5213 return(res);
5214}
5215
Daniel Veillard361d8452000-04-03 19:48:13 +00005216#endif /* LIBXML_XPATH_ENABLED */