blob: a8867a4d0cf6a605d330da6910f7ca0a4a94c64a [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer.
5 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#else
19#include "config.h"
20#endif
21
Daniel Veillard361d8452000-04-03 19:48:13 +000022#include "xmlversion.h"
23#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 Veillard1566d3a1999-07-15 14:24:29 +000052
Daniel Veillarddbfd6411999-12-28 16:35:14 +000053/* #define DEBUG */
54/* #define DEBUG_STEP */
55/* #define DEBUG_EXPR */
56
Daniel Veillard1566d3a1999-07-15 14:24:29 +000057/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000058 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000059 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000060 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000061double xmlXPathNAN = 0;
62double xmlXPathPINF = 1;
63double xmlXPathMINF = -1;
64
Daniel Veillardb05deb71999-08-10 19:04:08 +000065#ifndef isinf
66#ifndef HAVE_ISINF
67
68#if HAVE_FPCLASS
69
70int isinf(double d) {
71 fpclass_t type = fpclass(d);
72 switch (type) {
73 case FP_NINF:
74 return(-1);
75 case FP_PINF:
76 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000077 }
78 return(0);
79}
80
81#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
82
83#if HAVE_FP_CLASS_H
84#include <fp_class.h>
85#endif
86
87int isinf(double d) {
88#if HAVE_FP_CLASS
89 int fpclass = fp_class(d);
90#else
91 int fpclass = fp_class_d(d);
92#endif
93 if (fpclass == FP_POS_INF)
94 return(1);
95 if (fpclass == FP_NEG_INF)
96 return(-1);
97 return(0);
98}
99
100#elif defined(HAVE_CLASS)
101
102int isinf(double d) {
103 int fpclass = class(d);
104 if (fpclass == FP_PLUS_INF)
105 return(1);
106 if (fpclass == FP_MINUS_INF)
107 return(-1);
108 return(0);
109}
110#elif defined(finite) || defined(HAVE_FINITE)
111int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000112#elif defined(HUGE_VAL)
Daniel Veillardfc708e22000-04-08 13:17:27 +0000113int isinf(double x)
Daniel Veillard991e63d1999-08-15 23:32:28 +0000114{
115 if (x == HUGE_VAL)
116 return(1);
117 if (x == -HUGE_VAL)
118 return(-1);
119 return(0);
120}
121#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000122
123#endif /* ! HAVE_ISINF */
124#endif /* ! defined(isinf) */
125
126#ifndef isnan
127#ifndef HAVE_ISNAN
128
129#ifdef HAVE_ISNAND
130#define isnan(f) isnand(f)
131#endif /* HAVE_iSNAND */
132
133#endif /* ! HAVE_iSNAN */
134#endif /* ! defined(isnan) */
135
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000136/**
137 * xmlXPathInit:
138 *
139 * Initialize the XPath environment
140 */
141void
142xmlXPathInit(void) {
143 static int initialized = 0;
144
145 if (initialized) return;
146
147 xmlXPathNAN = 0;
148 xmlXPathNAN /= 0;
149
150 xmlXPathPINF = 1;
151 xmlXPathPINF /= 0;
152
153 xmlXPathMINF = -1;
154 xmlXPathMINF /= 0;
155
156 initialized = 1;
157}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000158
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000159FILE *xmlXPathDebug = NULL;
160
161#define TODO \
162 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
163 __FILE__, __LINE__);
164
165#define STRANGE \
166 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
167 __FILE__, __LINE__);
168
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000169double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000170void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000171
172/************************************************************************
173 * *
174 * Parser stacks related functions and macros *
175 * *
176 ************************************************************************/
177
178/*
179 * Generic function for accessing stacks in the Parser Context
180 */
181
182#define PUSH_AND_POP(type, name) \
183extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
184 if (ctxt->name##Nr >= ctxt->name##Max) { \
185 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000186 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000187 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
188 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000189 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000190 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000191 } \
192 } \
193 ctxt->name##Tab[ctxt->name##Nr] = value; \
194 ctxt->name = value; \
195 return(ctxt->name##Nr++); \
196} \
197extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
198 type ret; \
199 if (ctxt->name##Nr <= 0) return(0); \
200 ctxt->name##Nr--; \
201 if (ctxt->name##Nr > 0) \
202 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
203 else \
204 ctxt->name = NULL; \
205 ret = ctxt->name##Tab[ctxt->name##Nr]; \
206 ctxt->name##Tab[ctxt->name##Nr] = 0; \
207 return(ret); \
208} \
209
210PUSH_AND_POP(xmlXPathObjectPtr, value)
211
212/*
213 * Macros for accessing the content. Those should be used only by the parser,
214 * and not exported.
215 *
216 * Dirty macros, i.e. one need to make assumption on the context to use them
217 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000218 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000219 * CUR returns the current xmlChar value, i.e. a 8 bit value
220 * in ISO-Latin or UTF-8.
221 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000222 * only to compare to ASCII values otherwise it would break when
223 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000224 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000225 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000226 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000227 * strings within the parser.
228 * CURRENT Returns the current char value, with the full decoding of
229 * UTF-8 if we are using this mode. It returns an int.
230 * NEXT Skip to the next character, this does the proper decoding
231 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000232 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000233 */
234
235#define CUR (*ctxt->cur)
236#define SKIP(val) ctxt->cur += (val)
237#define NXT(val) ctxt->cur[(val)]
238#define CUR_PTR ctxt->cur
239
240#define SKIP_BLANKS \
241 while (IS_BLANK(*(ctxt->cur))) NEXT
242
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000243#define CURRENT (*ctxt->cur)
244#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000245
246/************************************************************************
247 * *
248 * Error handling routines *
249 * *
250 ************************************************************************/
251
252#define XPATH_EXPRESSION_OK 0
253#define XPATH_NUMBER_ERROR 1
254#define XPATH_UNFINISHED_LITERAL_ERROR 2
255#define XPATH_START_LITERAL_ERROR 3
256#define XPATH_VARIABLE_REF_ERROR 4
257#define XPATH_UNDEF_VARIABLE_ERROR 5
258#define XPATH_INVALID_PREDICATE_ERROR 6
259#define XPATH_EXPR_ERROR 7
260#define XPATH_UNCLOSED_ERROR 8
261#define XPATH_UNKNOWN_FUNC_ERROR 9
262#define XPATH_INVALID_OPERAND 10
263#define XPATH_INVALID_TYPE 11
264#define XPATH_INVALID_ARITY 12
265
266const char *xmlXPathErrorMessages[] = {
267 "Ok",
268 "Number encoding",
269 "Unfinished litteral",
270 "Start of litteral",
271 "Expected $ for variable reference",
272 "Undefined variable",
273 "Invalid predicate",
274 "Invalid expression",
275 "Missing closing curly brace",
276 "Unregistered function",
277 "Invalid operand",
278 "Invalid type",
279 "Invalid number of arguments",
280};
281
282/**
283 * xmlXPathError:
284 * @ctxt: the XPath Parser context
285 * @file: the file name
286 * @line: the line number
287 * @no: the error number
288 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000289 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000290 *
291 * Returns the newly created object.
292 */
293void
294xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
295 int line, int no) {
296 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000297 const xmlChar *cur;
298 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000299
300 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
301 xmlXPathErrorMessages[no]);
302
303 cur = ctxt->cur;
304 base = ctxt->base;
305 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
306 cur--;
307 }
308 n = 0;
309 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
310 cur--;
311 if ((*cur == '\n') || (*cur == '\r')) cur++;
312 base = cur;
313 n = 0;
314 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
315 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
316 n++;
317 }
318 fprintf(xmlXPathDebug, "\n");
319 cur = ctxt->cur;
320 while ((*cur == '\n') || (*cur == '\r'))
321 cur--;
322 n = 0;
323 while ((cur != base) && (n++ < 80)) {
324 fprintf(xmlXPathDebug, " ");
325 base++;
326 }
327 fprintf(xmlXPathDebug,"^\n");
328}
329
330#define CHECK_ERROR \
331 if (ctxt->error != XPATH_EXPRESSION_OK) return
332
333#define ERROR(X) \
334 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
335 ctxt->error = (X); return; }
336
Daniel Veillard991e63d1999-08-15 23:32:28 +0000337#define ERROR0(X) \
338 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
339 ctxt->error = (X); return(0); }
340
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000341#define CHECK_TYPE(typeval) \
342 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
343 ERROR(XPATH_INVALID_TYPE) \
344
345
346/************************************************************************
347 * *
348 * Routines to handle NodeSets *
349 * *
350 ************************************************************************/
351
352#define XML_NODESET_DEFAULT 10
353/**
354 * xmlXPathNodeSetCreate:
355 * @val: an initial xmlNodePtr, or NULL
356 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000357 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000358 *
359 * Returns the newly created object.
360 */
361xmlNodeSetPtr
362xmlXPathNodeSetCreate(xmlNodePtr val) {
363 xmlNodeSetPtr ret;
364
Daniel Veillard6454aec1999-09-02 22:04:43 +0000365 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000366 if (ret == NULL) {
367 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
368 return(NULL);
369 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000370 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000371 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000372 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000373 sizeof(xmlNodePtr));
374 if (ret->nodeTab == NULL) {
375 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
376 return(NULL);
377 }
378 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000379 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000380 ret->nodeMax = XML_NODESET_DEFAULT;
381 ret->nodeTab[ret->nodeNr++] = val;
382 }
383 return(ret);
384}
385
386/**
387 * xmlXPathNodeSetAdd:
388 * @cur: the initial node set
389 * @val: a new xmlNodePtr
390 *
391 * add a new xmlNodePtr ot an existing NodeSet
392 */
393void
394xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
395 int i;
396
397 if (val == NULL) return;
398
399 /*
400 * check against doublons
401 */
402 for (i = 0;i < cur->nodeNr;i++)
403 if (cur->nodeTab[i] == val) return;
404
405 /*
406 * grow the nodeTab if needed
407 */
408 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000409 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000410 sizeof(xmlNodePtr));
411 if (cur->nodeTab == NULL) {
412 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
413 return;
414 }
415 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000416 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000417 cur->nodeMax = XML_NODESET_DEFAULT;
418 } else if (cur->nodeNr == cur->nodeMax) {
419 xmlNodePtr *temp;
420
421 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000422 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000423 sizeof(xmlNodePtr));
424 if (temp == NULL) {
425 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
426 return;
427 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000428 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000429 }
430 cur->nodeTab[cur->nodeNr++] = val;
431}
432
433/**
434 * xmlXPathNodeSetMerge:
435 * @val1: the first NodeSet
436 * @val2: the second NodeSet
437 *
438 * Merges two nodesets, all nodes from @val2 are added to @val1
439 *
440 * Returns val1 once extended or NULL in case of error.
441 */
442xmlNodeSetPtr
443xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
444 int i;
445
446 if (val1 == NULL) return(NULL);
447 if (val2 == NULL) return(val1);
448
449 /*
450 * !!!!! this can be optimized a lot, knowing that both
451 * val1 and val2 already have unicity of their values.
452 */
453
454 for (i = 0;i < val2->nodeNr;i++)
455 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
456
457 return(val1);
458}
459
460/**
461 * xmlXPathNodeSetDel:
462 * @cur: the initial node set
463 * @val: an xmlNodePtr
464 *
465 * Removes an xmlNodePtr from an existing NodeSet
466 */
467void
468xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
469 int i;
470
471 if (cur == NULL) return;
472 if (val == NULL) return;
473
474 /*
475 * check against doublons
476 */
477 for (i = 0;i < cur->nodeNr;i++)
478 if (cur->nodeTab[i] == val) break;
479
480 if (i >= cur->nodeNr) {
481#ifdef DEBUG
482 fprintf(xmlXPathDebug,
483 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
484 val->name);
485#endif
486 return;
487 }
488 cur->nodeNr--;
489 for (;i < cur->nodeNr;i++)
490 cur->nodeTab[i] = cur->nodeTab[i + 1];
491 cur->nodeTab[cur->nodeNr] = NULL;
492}
493
494/**
495 * xmlXPathNodeSetRemove:
496 * @cur: the initial node set
497 * @val: the index to remove
498 *
499 * Removes an entry from an existing NodeSet list.
500 */
501void
502xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
503 if (cur == NULL) return;
504 if (val >= cur->nodeNr) return;
505 cur->nodeNr--;
506 for (;val < cur->nodeNr;val++)
507 cur->nodeTab[val] = cur->nodeTab[val + 1];
508 cur->nodeTab[cur->nodeNr] = NULL;
509}
510
511/**
512 * xmlXPathFreeNodeSet:
513 * @obj: the xmlNodeSetPtr to free
514 *
515 * Free the NodeSet compound (not the actual nodes !).
516 */
517void
518xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
519 if (obj == NULL) return;
520 if (obj->nodeTab != NULL) {
521#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000522 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000523#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000524 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000525 }
526#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000527 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000528#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000529 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000530}
531
Daniel Veillardb96e6431999-08-29 21:02:19 +0000532#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000533/**
534 * xmlXPathDebugNodeSet:
535 * @output: a FILE * for the output
536 * @obj: the xmlNodeSetPtr to free
537 *
538 * Quick display of a NodeSet
539 */
540void
541xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
542 int i;
543
544 if (output == NULL) output = xmlXPathDebug;
545 if (obj == NULL) {
546 fprintf(output, "NodeSet == NULL !\n");
547 return;
548 }
549 if (obj->nodeNr == 0) {
550 fprintf(output, "NodeSet is empty\n");
551 return;
552 }
553 if (obj->nodeTab == NULL) {
554 fprintf(output, " nodeTab == NULL !\n");
555 return;
556 }
557 for (i = 0; i < obj->nodeNr; i++) {
558 if (obj->nodeTab[i] == NULL) {
559 fprintf(output, " NULL !\n");
560 return;
561 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000562 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
563 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000564 fprintf(output, " /");
565 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000566 fprintf(output, " noname!");
567 else fprintf(output, " %s", obj->nodeTab[i]->name);
568 }
569 fprintf(output, "\n");
570}
571#endif
572
573/************************************************************************
574 * *
575 * Routines to handle Variable *
576 * *
577 * UNIMPLEMENTED CURRENTLY *
578 * *
579 ************************************************************************/
580
581/**
582 * xmlXPathVariablelookup:
583 * @ctxt: the XPath Parser context
584 * @prefix: the variable name namespace if any
585 * @name: the variable name
586 *
587 * Search in the Variable array of the context for the given
588 * variable value.
589 *
590 * UNIMPLEMENTED: always return NULL.
591 *
592 * Returns the value or NULL if not found
593 */
594xmlXPathObjectPtr
595xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000596 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000597 return(NULL);
598}
599
600/************************************************************************
601 * *
602 * Routines to handle Values *
603 * *
604 ************************************************************************/
605
606/* Allocations are terrible, one need to optimize all this !!! */
607
608/**
609 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000610 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000611 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000612 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000613 *
614 * Returns the newly created object.
615 */
616xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000617xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000618 xmlXPathObjectPtr ret;
619
Daniel Veillard6454aec1999-09-02 22:04:43 +0000620 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000621 if (ret == NULL) {
622 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
623 return(NULL);
624 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000625 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000626 ret->type = XPATH_NUMBER;
627 ret->floatval = val;
628 return(ret);
629}
630
631/**
632 * xmlXPathNewBoolean:
633 * @val: the boolean value
634 *
635 * Create a new xmlXPathObjectPtr of type boolean and of value @val
636 *
637 * Returns the newly created object.
638 */
639xmlXPathObjectPtr
640xmlXPathNewBoolean(int val) {
641 xmlXPathObjectPtr ret;
642
Daniel Veillard6454aec1999-09-02 22:04:43 +0000643 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000644 if (ret == NULL) {
645 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
646 return(NULL);
647 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000648 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000649 ret->type = XPATH_BOOLEAN;
650 ret->boolval = (val != 0);
651 return(ret);
652}
653
654/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000655 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000656 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000657 *
658 * Create a new xmlXPathObjectPtr of type string and of value @val
659 *
660 * Returns the newly created object.
661 */
662xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000663xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000664 xmlXPathObjectPtr ret;
665
Daniel Veillard6454aec1999-09-02 22:04:43 +0000666 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000667 if (ret == NULL) {
668 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
669 return(NULL);
670 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000671 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000672 ret->type = XPATH_STRING;
673 ret->stringval = xmlStrdup(val);
674 return(ret);
675}
676
677/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000678 * xmlXPathNewCString:
679 * @val: the char * value
680 *
681 * Create a new xmlXPathObjectPtr of type string and of value @val
682 *
683 * Returns the newly created object.
684 */
685xmlXPathObjectPtr
686xmlXPathNewCString(const char *val) {
687 xmlXPathObjectPtr ret;
688
Daniel Veillard6454aec1999-09-02 22:04:43 +0000689 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000690 if (ret == NULL) {
691 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
692 return(NULL);
693 }
694 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
695 ret->type = XPATH_STRING;
696 ret->stringval = xmlStrdup(BAD_CAST val);
697 return(ret);
698}
699
700/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000701 * xmlXPathNewNodeSet:
702 * @val: the NodePtr value
703 *
704 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
705 * it with the single Node @val
706 *
707 * Returns the newly created object.
708 */
709xmlXPathObjectPtr
710xmlXPathNewNodeSet(xmlNodePtr val) {
711 xmlXPathObjectPtr ret;
712
Daniel Veillard6454aec1999-09-02 22:04:43 +0000713 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000714 if (ret == NULL) {
715 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
716 return(NULL);
717 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000718 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000719 ret->type = XPATH_NODESET;
720 ret->nodesetval = xmlXPathNodeSetCreate(val);
721 return(ret);
722}
723
724/**
725 * xmlXPathNewNodeSetList:
726 * @val: an existing NodeSet
727 *
728 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
729 * it with the Nodeset @val
730 *
731 * Returns the newly created object.
732 */
733xmlXPathObjectPtr
734xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
735 xmlXPathObjectPtr ret;
736
Daniel Veillard6454aec1999-09-02 22:04:43 +0000737 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000738 if (ret == NULL) {
739 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
740 return(NULL);
741 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000742 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000743 ret->type = XPATH_NODESET;
744 ret->nodesetval = val;
745 return(ret);
746}
747
748/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000749 * xmlXPathFreeNodeSetList:
750 * @obj: an existing NodeSetList object
751 *
752 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
753 * the list contrary to xmlXPathFreeObject().
754 */
755void
756xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
757 if (obj == NULL) return;
758#ifdef DEBUG
759 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
760#endif
761 xmlFree(obj);
762}
763
764/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000765 * xmlXPathFreeObject:
766 * @obj: the object to free
767 *
768 * Free up an xmlXPathObjectPtr object.
769 */
770void
771xmlXPathFreeObject(xmlXPathObjectPtr obj) {
772 if (obj == NULL) return;
773 if (obj->nodesetval != NULL)
774 xmlXPathFreeNodeSet(obj->nodesetval);
775 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000776 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000777#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000778 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000779#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000780 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000781}
782
783/************************************************************************
784 * *
785 * Routines to handle XPath contexts *
786 * *
787 ************************************************************************/
788
789/**
790 * xmlXPathNewContext:
791 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000792 *
793 * Create a new xmlXPathContext
794 *
795 * Returns the xmlXPathContext just allocated.
796 */
797xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000798xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000799 xmlXPathContextPtr ret;
800
Daniel Veillard6454aec1999-09-02 22:04:43 +0000801 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000802 if (ret == NULL) {
803 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
804 return(NULL);
805 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000806 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000807 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000808 /***********
809 ret->node = (xmlNodePtr) doc;
810 ret->nodelist = xmlXPathNodeSetCreate(ret->node);
811 ***********/
812 ret->node = NULL;
813 ret->nodelist = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000814
815 ret->nb_variables = 0;
816 ret->max_variables = 0;
817 ret->variables = NULL;
818
819 ret->nb_types = 0;
820 ret->max_types = 0;
821 ret->types = NULL;
822
823 ret->nb_funcs = 0;
824 ret->max_funcs = 0;
825 ret->funcs = NULL;
826
827 ret->nb_axis = 0;
828 ret->max_axis = 0;
829 ret->axis = NULL;
830
Daniel Veillardb96e6431999-08-29 21:02:19 +0000831 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000832 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000833 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000834 return(ret);
835}
836
837/**
838 * xmlXPathFreeContext:
839 * @ctxt: the context to free
840 *
841 * Free up an xmlXPathContext
842 */
843void
844xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000845 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000846 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000847
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000848 /***********
849 if (ctxt->nodelist != NULL)
850 xmlXPathFreeNodeSet(ctxt->nodelist);
851 ***********/
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000852#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000853 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000854#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000855 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000856}
857
858/************************************************************************
859 * *
860 * Routines to handle XPath parser contexts *
861 * *
862 ************************************************************************/
863
864#define CHECK_CTXT \
865 if (ctxt == NULL) { \
866 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
867 __FILE__, __LINE__); \
868 } \
869
870
871#define CHECK_CONTEXT \
872 if (ctxt == NULL) { \
873 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
874 __FILE__, __LINE__); \
875 } \
876 if (ctxt->doc == NULL) { \
877 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
878 __FILE__, __LINE__); \
879 } \
Daniel Veillardcf461992000-03-14 18:30:20 +0000880 if (ctxt->doc->children == NULL) { \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000881 fprintf(xmlXPathDebug, \
882 "%s:%d Internal error: document without root\n", \
883 __FILE__, __LINE__); \
884 } \
885
886
887/**
888 * xmlXPathNewParserContext:
889 * @str: the XPath expression
890 * @ctxt: the XPath context
891 *
892 * Create a new xmlXPathParserContext
893 *
894 * Returns the xmlXPathParserContext just allocated.
895 */
896xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000897xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000898 xmlXPathParserContextPtr ret;
899
Daniel Veillard6454aec1999-09-02 22:04:43 +0000900 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000901 if (ret == NULL) {
902 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
903 return(NULL);
904 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000905 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000906 ret->cur = ret->base = str;
907 ret->context = ctxt;
908
909 /* Allocate the value stack */
910 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000911 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000912 ret->valueNr = 0;
913 ret->valueMax = 10;
914 ret->value = NULL;
915 return(ret);
916}
917
918/**
919 * xmlXPathFreeParserContext:
920 * @ctxt: the context to free
921 *
922 * Free up an xmlXPathParserContext
923 */
924void
925xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
926 if (ctxt->valueTab != NULL) {
927#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000928 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000929#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000930 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000931 }
932#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000933 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000934#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000935 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000936}
937
938/************************************************************************
939 * *
940 * The implicit core function library *
941 * *
942 ************************************************************************/
943
944/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000945 * Auto-pop and cast to a number
946 */
947void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
948
949#define CHECK_ARITY(x) \
950 if (nargs != (x)) { \
951 ERROR(XPATH_INVALID_ARITY); \
952 } \
953
954
955#define POP_FLOAT \
956 arg = valuePop(ctxt); \
957 if (arg == NULL) { \
958 ERROR(XPATH_INVALID_OPERAND); \
959 } \
960 if (arg->type != XPATH_NUMBER) { \
961 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000962 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000963 arg = valuePop(ctxt); \
964 }
965
966/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000967 * xmlXPathEqualNodeSetString
968 * @arg: the nodeset object argument
969 * @str: the string to compare to.
970 *
971 * Implement the equal operation on XPath objects content: @arg1 == @arg2
972 * If one object to be compared is a node-set and the other is a string,
973 * then the comparison will be true if and only if there is a node in
974 * the node-set such that the result of performing the comparison on the
975 * string-value of the node and the other string is true.
976 *
977 * Returns 0 or 1 depending on the results of the test.
978 */
979int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000980xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000981 int i;
982 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000983 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000984
985 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
986 return(0);
987 ns = arg->nodesetval;
988 for (i = 0;i < ns->nodeNr;i++) {
989 str2 = xmlNodeGetContent(ns->nodeTab[i]);
990 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000991 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000992 return(1);
993 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000994 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000995 }
996 return(0);
997}
998
999/**
1000 * xmlXPathEqualNodeSetFloat
1001 * @arg: the nodeset object argument
1002 * @f: the float to compare to
1003 *
1004 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1005 * If one object to be compared is a node-set and the other is a number,
1006 * then the comparison will be true if and only if there is a node in
1007 * the node-set such that the result of performing the comparison on the
1008 * number to be compared and on the result of converting the string-value
1009 * of that node to a number using the number function is true.
1010 *
1011 * Returns 0 or 1 depending on the results of the test.
1012 */
1013int
1014xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001015 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001016
1017 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1018 return(0);
1019
1020 if (isnan(f))
1021 sprintf(buf, "NaN");
1022 else if (isinf(f) > 0)
1023 sprintf(buf, "+Infinity");
1024 else if (isinf(f) < 0)
1025 sprintf(buf, "-Infinity");
1026 else
1027 sprintf(buf, "%0g", f);
1028
Daniel Veillardb96e6431999-08-29 21:02:19 +00001029 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001030}
1031
1032
1033/**
1034 * xmlXPathEqualNodeSets
1035 * @arg1: first nodeset object argument
1036 * @arg2: second nodeset object argument
1037 *
1038 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1039 * If both objects to be compared are node-sets, then the comparison
1040 * will be true if and only if there is a node in the first node-set and
1041 * a node in the second node-set such that the result of performing the
1042 * comparison on the string-values of the two nodes is true.
1043 *
1044 * (needless to say, this is a costly operation)
1045 *
1046 * Returns 0 or 1 depending on the results of the test.
1047 */
1048int
1049xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1050 int i;
1051 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001052 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001053
1054 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1055 return(0);
1056 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1057 return(0);
1058
1059 ns = arg1->nodesetval;
1060 for (i = 0;i < ns->nodeNr;i++) {
1061 str = xmlNodeGetContent(ns->nodeTab[i]);
1062 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001063 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001064 return(1);
1065 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001066 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001067 }
1068 return(0);
1069}
1070
1071/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001072 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001073 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001074 *
1075 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1076 *
1077 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001078 */
1079int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001080xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1081 xmlXPathObjectPtr arg1, arg2;
1082 int ret = 0;
1083
1084 arg1 = valuePop(ctxt);
1085 if (arg1 == NULL)
1086 ERROR0(XPATH_INVALID_OPERAND);
1087
1088 arg2 = valuePop(ctxt);
1089 if (arg2 == NULL) {
1090 xmlXPathFreeObject(arg1);
1091 ERROR0(XPATH_INVALID_OPERAND);
1092 }
1093
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001094 if (arg1 == arg2) {
1095#ifdef DEBUG_EXPR
1096 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1097#endif
1098 return(1);
1099 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001100
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001101 switch (arg1->type) {
1102 case XPATH_UNDEFINED:
1103#ifdef DEBUG_EXPR
1104 fprintf(xmlXPathDebug, "Equal: undefined\n");
1105#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001106 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001107 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001108 switch (arg2->type) {
1109 case XPATH_UNDEFINED:
1110#ifdef DEBUG_EXPR
1111 fprintf(xmlXPathDebug, "Equal: undefined\n");
1112#endif
1113 break;
1114 case XPATH_NODESET:
1115 ret = xmlXPathEqualNodeSets(arg1, arg2);
1116 break;
1117 case XPATH_BOOLEAN:
1118 if ((arg1->nodesetval == NULL) ||
1119 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1120 else
1121 ret = 1;
1122 ret = (ret == arg2->boolval);
1123 break;
1124 case XPATH_NUMBER:
1125 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1126 break;
1127 case XPATH_STRING:
1128 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1129 break;
1130 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001131 break;
1132 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001133 switch (arg2->type) {
1134 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001135#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001136 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001137#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001138 break;
1139 case XPATH_NODESET:
1140 if ((arg2->nodesetval == NULL) ||
1141 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1142 else
1143 ret = 1;
1144 break;
1145 case XPATH_BOOLEAN:
1146#ifdef DEBUG_EXPR
1147 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1148 arg1->boolval, arg2->boolval);
1149#endif
1150 ret = (arg1->boolval == arg2->boolval);
1151 break;
1152 case XPATH_NUMBER:
1153 if (arg2->floatval) ret = 1;
1154 else ret = 0;
1155 ret = (arg1->boolval == ret);
1156 break;
1157 case XPATH_STRING:
1158 if ((arg2->stringval == NULL) ||
1159 (arg2->stringval[0] == 0)) ret = 0;
1160 else
1161 ret = 1;
1162 ret = (arg1->boolval == ret);
1163 break;
1164 }
1165 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001166 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001167 switch (arg2->type) {
1168 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001169#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001170 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001171#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001172 break;
1173 case XPATH_NODESET:
1174 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1175 break;
1176 case XPATH_BOOLEAN:
1177 if (arg1->floatval) ret = 1;
1178 else ret = 0;
1179 ret = (arg2->boolval == ret);
1180 break;
1181 case XPATH_STRING:
1182 valuePush(ctxt, arg2);
1183 xmlXPathNumberFunction(ctxt, 1);
1184 arg2 = valuePop(ctxt);
1185 /* no break on purpose */
1186 case XPATH_NUMBER:
1187 ret = (arg1->floatval == arg2->floatval);
1188 break;
1189 }
1190 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001191 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001192 switch (arg2->type) {
1193 case XPATH_UNDEFINED:
1194#ifdef DEBUG_EXPR
1195 fprintf(xmlXPathDebug, "Equal: undefined\n");
1196#endif
1197 break;
1198 case XPATH_NODESET:
1199 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1200 break;
1201 case XPATH_BOOLEAN:
1202 if ((arg1->stringval == NULL) ||
1203 (arg1->stringval[0] == 0)) ret = 0;
1204 else
1205 ret = 1;
1206 ret = (arg2->boolval == ret);
1207 break;
1208 case XPATH_STRING:
1209 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1210 break;
1211 case XPATH_NUMBER:
1212 valuePush(ctxt, arg1);
1213 xmlXPathNumberFunction(ctxt, 1);
1214 arg1 = valuePop(ctxt);
1215 ret = (arg1->floatval == arg2->floatval);
1216 break;
1217 }
1218 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001219 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001220 xmlXPathFreeObject(arg1);
1221 xmlXPathFreeObject(arg2);
1222 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001223}
1224
1225/**
1226 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001227 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001228 * @inf: less than (1) or greater than (2)
1229 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001230 *
1231 * Implement the compare operation on XPath objects:
1232 * @arg1 < @arg2 (1, 1, ...
1233 * @arg1 <= @arg2 (1, 0, ...
1234 * @arg1 > @arg2 (0, 1, ...
1235 * @arg1 >= @arg2 (0, 0, ...
1236 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001237 * When neither object to be compared is a node-set and the operator is
1238 * <=, <, >=, >, then the objects are compared by converted both objects
1239 * to numbers and comparing the numbers according to IEEE 754. The <
1240 * comparison will be true if and only if the first number is less than the
1241 * second number. The <= comparison will be true if and only if the first
1242 * number is less than or equal to the second number. The > comparison
1243 * will be true if and only if the first number is greater than the second
1244 * number. The >= comparison will be true if and only if the first number
1245 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001246 */
1247int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001248xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1249 int ret = 0;
1250 xmlXPathObjectPtr arg1, arg2;
1251
1252 arg2 = valuePop(ctxt);
1253 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1254 if (arg2 != NULL)
1255 xmlXPathFreeObject(arg2);
1256 ERROR0(XPATH_INVALID_OPERAND);
1257 }
1258
1259 arg1 = valuePop(ctxt);
1260 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1261 if (arg1 != NULL)
1262 xmlXPathFreeObject(arg1);
1263 xmlXPathFreeObject(arg2);
1264 ERROR0(XPATH_INVALID_OPERAND);
1265 }
1266
1267 if (arg1->type != XPATH_NUMBER) {
1268 valuePush(ctxt, arg1);
1269 xmlXPathNumberFunction(ctxt, 1);
1270 arg1 = valuePop(ctxt);
1271 }
1272 if (arg1->type != XPATH_NUMBER) {
1273 xmlXPathFreeObject(arg1);
1274 xmlXPathFreeObject(arg2);
1275 ERROR0(XPATH_INVALID_OPERAND);
1276 }
1277 if (arg2->type != XPATH_NUMBER) {
1278 valuePush(ctxt, arg2);
1279 xmlXPathNumberFunction(ctxt, 1);
1280 arg2 = valuePop(ctxt);
1281 }
1282 if (arg2->type != XPATH_NUMBER) {
1283 xmlXPathFreeObject(arg1);
1284 xmlXPathFreeObject(arg2);
1285 ERROR0(XPATH_INVALID_OPERAND);
1286 }
1287 /*
1288 * Add tests for infinity and nan
1289 * => feedback on 3.4 for Inf and NaN
1290 */
1291 if (inf && strict)
1292 ret = (arg1->floatval < arg2->floatval);
1293 else if (inf && !strict)
1294 ret = (arg1->floatval <= arg2->floatval);
1295 else if (!inf && strict)
1296 ret = (arg1->floatval > arg2->floatval);
1297 else if (!inf && !strict)
1298 ret = (arg1->floatval >= arg2->floatval);
1299 xmlXPathFreeObject(arg1);
1300 xmlXPathFreeObject(arg2);
1301 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001302}
1303
1304/**
1305 * xmlXPathValueFlipSign:
1306 * @ctxt: the XPath Parser context
1307 *
1308 * Implement the unary - operation on an XPath object
1309 * The numeric operators convert their operands to numbers as if
1310 * by calling the number function.
1311 */
1312void
1313xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1314 xmlXPathObjectPtr arg;
1315
1316 POP_FLOAT
1317 arg->floatval = -arg->floatval;
1318 valuePush(ctxt, arg);
1319}
1320
1321/**
1322 * xmlXPathAddValues:
1323 * @ctxt: the XPath Parser context
1324 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001325 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001326 * The numeric operators convert their operands to numbers as if
1327 * by calling the number function.
1328 */
1329void
1330xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1331 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001332 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001333
1334 POP_FLOAT
1335 val = arg->floatval;
1336 xmlXPathFreeObject(arg);
1337
1338 POP_FLOAT
1339 arg->floatval += val;
1340 valuePush(ctxt, arg);
1341}
1342
1343/**
1344 * xmlXPathSubValues:
1345 * @ctxt: the XPath Parser context
1346 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001347 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001348 * The numeric operators convert their operands to numbers as if
1349 * by calling the number function.
1350 */
1351void
1352xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1353 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001354 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001355
1356 POP_FLOAT
1357 val = arg->floatval;
1358 xmlXPathFreeObject(arg);
1359
1360 POP_FLOAT
1361 arg->floatval -= val;
1362 valuePush(ctxt, arg);
1363}
1364
1365/**
1366 * xmlXPathMultValues:
1367 * @ctxt: the XPath Parser context
1368 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001369 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001370 * The numeric operators convert their operands to numbers as if
1371 * by calling the number function.
1372 */
1373void
1374xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1375 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001376 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001377
1378 POP_FLOAT
1379 val = arg->floatval;
1380 xmlXPathFreeObject(arg);
1381
1382 POP_FLOAT
1383 arg->floatval *= val;
1384 valuePush(ctxt, arg);
1385}
1386
1387/**
1388 * xmlXPathDivValues:
1389 * @ctxt: the XPath Parser context
1390 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001391 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001392 * The numeric operators convert their operands to numbers as if
1393 * by calling the number function.
1394 */
1395void
1396xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1397 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001398 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001399
1400 POP_FLOAT
1401 val = arg->floatval;
1402 xmlXPathFreeObject(arg);
1403
1404 POP_FLOAT
1405 arg->floatval /= val;
1406 valuePush(ctxt, arg);
1407}
1408
1409/**
1410 * xmlXPathModValues:
1411 * @ctxt: the XPath Parser context
1412 *
1413 * Implement the div operation on XPath objects: @arg1 / @arg2
1414 * The numeric operators convert their operands to numbers as if
1415 * by calling the number function.
1416 */
1417void
1418xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1419 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001420 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001421
1422 POP_FLOAT
1423 val = arg->floatval;
1424 xmlXPathFreeObject(arg);
1425
1426 POP_FLOAT
1427 arg->floatval /= val;
1428 valuePush(ctxt, arg);
1429}
1430
1431/************************************************************************
1432 * *
1433 * The traversal functions *
1434 * *
1435 ************************************************************************/
1436
1437#define AXIS_ANCESTOR 1
1438#define AXIS_ANCESTOR_OR_SELF 2
1439#define AXIS_ATTRIBUTE 3
1440#define AXIS_CHILD 4
1441#define AXIS_DESCENDANT 5
1442#define AXIS_DESCENDANT_OR_SELF 6
1443#define AXIS_FOLLOWING 7
1444#define AXIS_FOLLOWING_SIBLING 8
1445#define AXIS_NAMESPACE 9
1446#define AXIS_PARENT 10
1447#define AXIS_PRECEDING 11
1448#define AXIS_PRECEDING_SIBLING 12
1449#define AXIS_SELF 13
1450
1451/*
1452 * A traversal function enumerates nodes along an axis.
1453 * Initially it must be called with NULL, and it indicates
1454 * termination on the axis by returning NULL.
1455 */
1456typedef xmlNodePtr (*xmlXPathTraversalFunction)
1457 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1458
1459/**
1460 * mlXPathNextSelf:
1461 * @ctxt: the XPath Parser context
1462 * @cur: the current node in the traversal
1463 *
1464 * Traversal function for the "self" direction
1465 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001466 *
1467 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001468 */
1469xmlNodePtr
1470xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1471 if (cur == NULL)
1472 return(ctxt->context->node);
1473 return(NULL);
1474}
1475
1476/**
1477 * mlXPathNextChild:
1478 * @ctxt: the XPath Parser context
1479 * @cur: the current node in the traversal
1480 *
1481 * Traversal function for the "child" direction
1482 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001483 *
1484 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001485 */
1486xmlNodePtr
1487xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001488 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001489 if (ctxt->context->node == NULL) return(NULL);
1490 switch (ctxt->context->node->type) {
1491 case XML_ELEMENT_NODE:
1492 case XML_TEXT_NODE:
1493 case XML_CDATA_SECTION_NODE:
1494 case XML_ENTITY_REF_NODE:
1495 case XML_ENTITY_NODE:
1496 case XML_PI_NODE:
1497 case XML_COMMENT_NODE:
1498 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001499 case XML_DTD_NODE:
1500 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001501 case XML_DOCUMENT_NODE:
1502 case XML_DOCUMENT_TYPE_NODE:
1503 case XML_DOCUMENT_FRAG_NODE:
1504 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001505 return(((xmlDocPtr) ctxt->context->node)->children);
1506 case XML_ELEMENT_DECL:
1507 case XML_ATTRIBUTE_DECL:
1508 case XML_ENTITY_DECL:
1509 case XML_ATTRIBUTE_NODE:
1510 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001511 }
1512 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001513 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001514 if ((cur->type == XML_DOCUMENT_NODE) ||
1515 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001516 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001517 return(cur->next);
1518}
1519
1520/**
1521 * mlXPathNextDescendant:
1522 * @ctxt: the XPath Parser context
1523 * @cur: the current node in the traversal
1524 *
1525 * Traversal function for the "descendant" direction
1526 * the descendant axis contains the descendants of the context node in document
1527 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001528 *
1529 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001530 */
1531xmlNodePtr
1532xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001533 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001534 if (ctxt->context->node == NULL)
1535 return(NULL);
1536 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1537 return(NULL);
1538
Daniel Veillardb05deb71999-08-10 19:04:08 +00001539 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00001540 return(ctxt->context->doc->children);
1541 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001542 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001543
Daniel Veillardcf461992000-03-14 18:30:20 +00001544 if (cur->children != NULL) return(cur->children);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001545 if (cur->next != NULL) return(cur->next);
1546
1547 do {
1548 cur = cur->parent;
1549 if (cur == NULL) return(NULL);
1550 if (cur == ctxt->context->node) return(NULL);
1551 if (cur->next != NULL) {
1552 cur = cur->next;
1553 return(cur);
1554 }
1555 } while (cur != NULL);
1556 return(cur);
1557}
1558
1559/**
1560 * mlXPathNextDescendantOrSelf:
1561 * @ctxt: the XPath Parser context
1562 * @cur: the current node in the traversal
1563 *
1564 * Traversal function for the "descendant-or-self" direction
1565 * the descendant-or-self axis contains the context node and the descendants
1566 * of the context node in document order; thus the context node is the first
1567 * node on the axis, and the first child of the context node is the second node
1568 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001569 *
1570 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001571 */
1572xmlNodePtr
1573xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001574 if (cur == NULL) {
1575 if (ctxt->context->node == NULL)
1576 return(NULL);
1577 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1578 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001579 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001580 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001581
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001582 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001583}
1584
1585/**
1586 * xmlXPathNextParent:
1587 * @ctxt: the XPath Parser context
1588 * @cur: the current node in the traversal
1589 *
1590 * Traversal function for the "parent" direction
1591 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001592 *
1593 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001594 */
1595xmlNodePtr
1596xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1597 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001598 * the parent of an attribute or namespace node is the element
1599 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001600 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001601 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001602 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001603 if (ctxt->context->node == NULL) return(NULL);
1604 switch (ctxt->context->node->type) {
1605 case XML_ELEMENT_NODE:
1606 case XML_TEXT_NODE:
1607 case XML_CDATA_SECTION_NODE:
1608 case XML_ENTITY_REF_NODE:
1609 case XML_ENTITY_NODE:
1610 case XML_PI_NODE:
1611 case XML_COMMENT_NODE:
1612 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001613 case XML_DTD_NODE:
1614 case XML_ELEMENT_DECL:
1615 case XML_ATTRIBUTE_DECL:
1616 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001617 if (ctxt->context->node->parent == NULL)
1618 return((xmlNodePtr) ctxt->context->doc);
1619 return(ctxt->context->node->parent);
1620 case XML_ATTRIBUTE_NODE: {
1621 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1622
Daniel Veillardcf461992000-03-14 18:30:20 +00001623 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001624 }
1625 case XML_DOCUMENT_NODE:
1626 case XML_DOCUMENT_TYPE_NODE:
1627 case XML_DOCUMENT_FRAG_NODE:
1628 case XML_HTML_DOCUMENT_NODE:
1629 return(NULL);
1630 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001631 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001632 return(NULL);
1633}
1634
1635/**
1636 * xmlXPathNextAncestor:
1637 * @ctxt: the XPath Parser context
1638 * @cur: the current node in the traversal
1639 *
1640 * Traversal function for the "ancestor" direction
1641 * the ancestor axis contains the ancestors of the context node; the ancestors
1642 * of the context node consist of the parent of context node and the parent's
1643 * parent and so on; the nodes are ordered in reverse document order; thus the
1644 * parent is the first node on the axis, and the parent's parent is the second
1645 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001646 *
1647 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001648 */
1649xmlNodePtr
1650xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1651 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001652 * the parent of an attribute or namespace node is the element
1653 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001654 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001655 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001656 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001657 if (ctxt->context->node == NULL) return(NULL);
1658 switch (ctxt->context->node->type) {
1659 case XML_ELEMENT_NODE:
1660 case XML_TEXT_NODE:
1661 case XML_CDATA_SECTION_NODE:
1662 case XML_ENTITY_REF_NODE:
1663 case XML_ENTITY_NODE:
1664 case XML_PI_NODE:
1665 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001666 case XML_DTD_NODE:
1667 case XML_ELEMENT_DECL:
1668 case XML_ATTRIBUTE_DECL:
1669 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001670 case XML_NOTATION_NODE:
1671 if (ctxt->context->node->parent == NULL)
1672 return((xmlNodePtr) ctxt->context->doc);
1673 return(ctxt->context->node->parent);
1674 case XML_ATTRIBUTE_NODE: {
1675 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
1676
Daniel Veillardcf461992000-03-14 18:30:20 +00001677 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001678 }
1679 case XML_DOCUMENT_NODE:
1680 case XML_DOCUMENT_TYPE_NODE:
1681 case XML_DOCUMENT_FRAG_NODE:
1682 case XML_HTML_DOCUMENT_NODE:
1683 return(NULL);
1684 }
1685 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001686 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001687 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00001688 return((xmlNodePtr) ctxt->context->doc);
1689 if (cur == (xmlNodePtr) ctxt->context->doc)
1690 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001691 switch (cur->type) {
1692 case XML_ELEMENT_NODE:
1693 case XML_TEXT_NODE:
1694 case XML_CDATA_SECTION_NODE:
1695 case XML_ENTITY_REF_NODE:
1696 case XML_ENTITY_NODE:
1697 case XML_PI_NODE:
1698 case XML_COMMENT_NODE:
1699 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001700 case XML_DTD_NODE:
1701 case XML_ELEMENT_DECL:
1702 case XML_ATTRIBUTE_DECL:
1703 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001704 return(cur->parent);
1705 case XML_ATTRIBUTE_NODE: {
1706 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1707
Daniel Veillardcf461992000-03-14 18:30:20 +00001708 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001709 }
1710 case XML_DOCUMENT_NODE:
1711 case XML_DOCUMENT_TYPE_NODE:
1712 case XML_DOCUMENT_FRAG_NODE:
1713 case XML_HTML_DOCUMENT_NODE:
1714 return(NULL);
1715 }
1716 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001717}
1718
1719/**
1720 * xmlXPathNextAncestorOrSelf:
1721 * @ctxt: the XPath Parser context
1722 * @cur: the current node in the traversal
1723 *
1724 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001725 * he ancestor-or-self axis contains the context node and ancestors of
1726 * the context node in reverse document order; thus the context node is
1727 * the first node on the axis, and the context node's parent the second;
1728 * parent here is defined the same as with the parent axis.
1729 *
1730 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001731 */
1732xmlNodePtr
1733xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001734 if (cur == NULL)
1735 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001736 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001737}
1738
1739/**
1740 * xmlXPathNextFollowingSibling:
1741 * @ctxt: the XPath Parser context
1742 * @cur: the current node in the traversal
1743 *
1744 * Traversal function for the "following-sibling" direction
1745 * The following-sibling axis contains the following siblings of the context
1746 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001747 *
1748 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001749 */
1750xmlNodePtr
1751xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001752 if (cur == (xmlNodePtr) ctxt->context->doc)
1753 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001754 if (cur == NULL)
1755 return(ctxt->context->node->next);
1756 return(cur->next);
1757}
1758
1759/**
1760 * xmlXPathNextPrecedingSibling:
1761 * @ctxt: the XPath Parser context
1762 * @cur: the current node in the traversal
1763 *
1764 * Traversal function for the "preceding-sibling" direction
1765 * The preceding-sibling axis contains the preceding siblings of the context
1766 * node in reverse document order; the first preceding sibling is first on the
1767 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001768 *
1769 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001770 */
1771xmlNodePtr
1772xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001773 if (cur == (xmlNodePtr) ctxt->context->doc)
1774 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001775 if (cur == NULL)
1776 return(ctxt->context->node->prev);
1777 return(cur->prev);
1778}
1779
1780/**
1781 * xmlXPathNextFollowing:
1782 * @ctxt: the XPath Parser context
1783 * @cur: the current node in the traversal
1784 *
1785 * Traversal function for the "following" direction
1786 * The following axis contains all nodes in the same document as the context
1787 * node that are after the context node in document order, excluding any
1788 * descendants and excluding attribute nodes and namespace nodes; the nodes
1789 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001790 *
1791 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001792 */
1793xmlNodePtr
1794xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001795 if (cur == (xmlNodePtr) ctxt->context->doc)
1796 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001797 if (cur == NULL)
1798 return(ctxt->context->node->next);; /* !!!!!!!!! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001799 if (cur->children != NULL) return(cur->children);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001800 if (cur->next != NULL) return(cur->next);
1801
1802 do {
1803 cur = cur->parent;
1804 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00001805 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001806 if (cur->next != NULL) {
1807 cur = cur->next;
1808 return(cur);
1809 }
1810 } while (cur != NULL);
1811 return(cur);
1812}
1813
1814/**
1815 * xmlXPathNextPreceding:
1816 * @ctxt: the XPath Parser context
1817 * @cur: the current node in the traversal
1818 *
1819 * Traversal function for the "preceding" direction
1820 * the preceding axis contains all nodes in the same document as the context
1821 * node that are before the context node in document order, excluding any
1822 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1823 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001824 *
1825 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001826 */
1827xmlNodePtr
1828xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001829 if (cur == (xmlNodePtr) ctxt->context->doc)
1830 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001831 if (cur == NULL)
1832 return(ctxt->context->node->prev); /* !!!!!!!!! */
1833 if (cur->last != NULL) return(cur->last);
1834 if (cur->prev != NULL) return(cur->prev);
1835
1836 do {
1837 cur = cur->parent;
1838 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00001839 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001840 if (cur->prev != NULL) {
1841 cur = cur->prev;
1842 return(cur);
1843 }
1844 } while (cur != NULL);
1845 return(cur);
1846}
1847
1848/**
1849 * xmlXPathNextNamespace:
1850 * @ctxt: the XPath Parser context
1851 * @cur: the current attribute in the traversal
1852 *
1853 * Traversal function for the "namespace" direction
1854 * the namespace axis contains the namespace nodes of the context node;
1855 * the order of nodes on this axis is implementation-defined; the axis will
1856 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001857 *
1858 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001859 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001860xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001861xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001862 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1863 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001864 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001865 ctxt->context->namespaces =
1866 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1867 if (ctxt->context->namespaces == NULL) return(NULL);
1868 ctxt->context->nsNr = 0;
1869 }
1870 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001871}
1872
1873/**
1874 * xmlXPathNextAttribute:
1875 * @ctxt: the XPath Parser context
1876 * @cur: the current attribute in the traversal
1877 *
1878 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001879 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001880 *
1881 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001882 */
1883xmlAttrPtr
1884xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001885 if (cur == NULL) {
1886 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1887 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001888 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001889 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001890 return(cur->next);
1891}
1892
1893/************************************************************************
1894 * *
1895 * NodeTest Functions *
1896 * *
1897 ************************************************************************/
1898
1899#define NODE_TEST_NONE 0
1900#define NODE_TEST_TYPE 1
1901#define NODE_TEST_PI 2
1902#define NODE_TEST_ALL 3
1903#define NODE_TEST_NS 4
1904#define NODE_TEST_NAME 5
1905
1906#define NODE_TYPE_COMMENT 50
1907#define NODE_TYPE_TEXT 51
1908#define NODE_TYPE_PI 52
1909#define NODE_TYPE_NODE 53
1910
1911#define IS_FUNCTION 200
1912
1913/**
1914 * xmlXPathNodeCollectAndTest:
1915 * @ctxt: the XPath Parser context
1916 * @cur: the current node to test
1917 *
1918 * This is the function implementing a step: based on the current list
1919 * of nodes, it builds up a new list, looking at all nodes under that
1920 * axis and selecting them.
1921 *
1922 * Returns the new NodeSet resulting from the search.
1923 */
1924xmlNodeSetPtr
1925xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001926 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001927#ifdef DEBUG_STEP
1928 int n = 0, t = 0;
1929#endif
1930 int i;
1931 xmlNodeSetPtr ret;
1932 xmlXPathTraversalFunction next = NULL;
1933 xmlNodePtr cur = NULL;
1934
1935 if (ctxt->context->nodelist == NULL) {
1936 if (ctxt->context->node == NULL) {
1937 fprintf(xmlXPathDebug,
1938 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1939 __FILE__, __LINE__);
1940 return(NULL);
1941 }
1942 STRANGE
1943 return(NULL);
1944 }
1945#ifdef DEBUG_STEP
1946 fprintf(xmlXPathDebug, "new step : ");
1947#endif
1948 switch (axis) {
1949 case AXIS_ANCESTOR:
1950#ifdef DEBUG_STEP
1951 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1952#endif
1953 next = xmlXPathNextAncestor; break;
1954 case AXIS_ANCESTOR_OR_SELF:
1955#ifdef DEBUG_STEP
1956 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1957#endif
1958 next = xmlXPathNextAncestorOrSelf; break;
1959 case AXIS_ATTRIBUTE:
1960#ifdef DEBUG_STEP
1961 fprintf(xmlXPathDebug, "axis 'attributes' ");
1962#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001963 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001964 break;
1965 case AXIS_CHILD:
1966#ifdef DEBUG_STEP
1967 fprintf(xmlXPathDebug, "axis 'child' ");
1968#endif
1969 next = xmlXPathNextChild; break;
1970 case AXIS_DESCENDANT:
1971#ifdef DEBUG_STEP
1972 fprintf(xmlXPathDebug, "axis 'descendant' ");
1973#endif
1974 next = xmlXPathNextDescendant; break;
1975 case AXIS_DESCENDANT_OR_SELF:
1976#ifdef DEBUG_STEP
1977 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1978#endif
1979 next = xmlXPathNextDescendantOrSelf; break;
1980 case AXIS_FOLLOWING:
1981#ifdef DEBUG_STEP
1982 fprintf(xmlXPathDebug, "axis 'following' ");
1983#endif
1984 next = xmlXPathNextFollowing; break;
1985 case AXIS_FOLLOWING_SIBLING:
1986#ifdef DEBUG_STEP
1987 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1988#endif
1989 next = xmlXPathNextFollowingSibling; break;
1990 case AXIS_NAMESPACE:
1991#ifdef DEBUG_STEP
1992 fprintf(xmlXPathDebug, "axis 'namespace' ");
1993#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001994 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001995 break;
1996 case AXIS_PARENT:
1997#ifdef DEBUG_STEP
1998 fprintf(xmlXPathDebug, "axis 'parent' ");
1999#endif
2000 next = xmlXPathNextParent; break;
2001 case AXIS_PRECEDING:
2002#ifdef DEBUG_STEP
2003 fprintf(xmlXPathDebug, "axis 'preceding' ");
2004#endif
2005 next = xmlXPathNextPreceding; break;
2006 case AXIS_PRECEDING_SIBLING:
2007#ifdef DEBUG_STEP
2008 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
2009#endif
2010 next = xmlXPathNextPrecedingSibling; break;
2011 case AXIS_SELF:
2012#ifdef DEBUG_STEP
2013 fprintf(xmlXPathDebug, "axis 'self' ");
2014#endif
2015 next = xmlXPathNextSelf; break;
2016 }
2017 if (next == NULL) return(NULL);
2018 ret = xmlXPathNodeSetCreate(NULL);
2019#ifdef DEBUG_STEP
2020 fprintf(xmlXPathDebug, " context contains %d nodes\n",
2021 ctxt->context->nodelist->nodeNr);
2022 switch (test) {
2023 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002024 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002025 break;
2026 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002027 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002028 break;
2029 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002030 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002031 break;
2032 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002033 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002034 break;
2035 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002036 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002037 prefix);
2038 break;
2039 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002040 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002041 if (prefix != NULL)
2042 fprintf(xmlXPathDebug, " with namespace %s\n",
2043 prefix);
2044 break;
2045 }
2046 fprintf(xmlXPathDebug, "Testing : ");
2047#endif
2048 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
2049 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
2050
2051 cur = NULL;
2052 do {
2053 cur = next(ctxt, cur);
2054 if (cur == NULL) break;
2055#ifdef DEBUG_STEP
2056 t++;
2057 fprintf(xmlXPathDebug, " %s", cur->name);
2058#endif
2059 switch (test) {
2060 case NODE_TEST_NONE:
2061 STRANGE
2062 return(NULL);
2063 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002064 if ((cur->type == type) ||
2065 ((type == XML_ELEMENT_NODE) &&
2066 ((cur->type == XML_DOCUMENT_NODE) ||
2067 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002068#ifdef DEBUG_STEP
2069 n++;
2070#endif
2071 xmlXPathNodeSetAdd(ret, cur);
2072 }
2073 break;
2074 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002075 if (cur->type == XML_PI_NODE) {
2076 if ((name != NULL) &&
2077 (xmlStrcmp(name, cur->name)))
2078 break;
2079#ifdef DEBUG_STEP
2080 n++;
2081#endif
2082 xmlXPathNodeSetAdd(ret, cur);
2083 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002084 break;
2085 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002086 if ((cur->type == XML_ELEMENT_NODE) ||
2087 (cur->type == XML_ATTRIBUTE_NODE)) {
2088 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002089#ifdef DEBUG_STEP
2090 n++;
2091#endif
2092 xmlXPathNodeSetAdd(ret, cur);
2093 }
2094 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002095 case NODE_TEST_NS: {
2096 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002097 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002098 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002099 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002100 switch (cur->type) {
2101 case XML_ELEMENT_NODE:
2102 if (!xmlStrcmp(name, cur->name) &&
2103 (((prefix == NULL) ||
2104 ((cur->ns != NULL) &&
2105 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002106#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002107 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002108#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002109 xmlXPathNodeSetAdd(ret, cur);
2110 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002111 break;
2112 case XML_ATTRIBUTE_NODE: {
2113 xmlAttrPtr attr = (xmlAttrPtr) cur;
2114 if (!xmlStrcmp(name, attr->name)) {
2115#ifdef DEBUG_STEP
2116 n++;
2117#endif
2118 xmlXPathNodeSetAdd(ret, cur);
2119 }
2120 break;
2121 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002122 default:
2123 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002124 }
2125 break;
2126
2127 }
2128 } while (cur != NULL);
2129 }
2130#ifdef DEBUG_STEP
2131 fprintf(xmlXPathDebug,
2132 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2133#endif
2134 return(ret);
2135}
2136
2137
2138/************************************************************************
2139 * *
2140 * Implicit tree core function library *
2141 * *
2142 ************************************************************************/
2143
2144/**
2145 * xmlXPathRoot:
2146 * @ctxt: the XPath Parser context
2147 *
2148 * Initialize the context to the root of the document
2149 */
2150void
2151xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2152 if (ctxt->context->nodelist != NULL)
2153 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002154 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2155 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002156}
2157
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002158/************************************************************************
2159 * *
2160 * The explicit core function library *
2161 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2162 * *
2163 ************************************************************************/
2164
2165
2166/**
2167 * xmlXPathLastFunction:
2168 * @ctxt: the XPath Parser context
2169 *
2170 * Implement the last() XPath function
2171 * The last function returns the number of nodes in the context node list.
2172 */
2173void
2174xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2175 CHECK_ARITY(0);
2176 if ((ctxt->context->nodelist == NULL) ||
2177 (ctxt->context->node == NULL) ||
2178 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002179 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002180 } else {
2181 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002182 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002183 }
2184}
2185
2186/**
2187 * xmlXPathPositionFunction:
2188 * @ctxt: the XPath Parser context
2189 *
2190 * Implement the position() XPath function
2191 * The position function returns the position of the context node in the
2192 * context node list. The first position is 1, and so the last positionr
2193 * will be equal to last().
2194 */
2195void
2196xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2197 int i;
2198
2199 CHECK_ARITY(0);
2200 if ((ctxt->context->nodelist == NULL) ||
2201 (ctxt->context->node == NULL) ||
2202 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002203 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002204 }
2205 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2206 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002207 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002208 return;
2209 }
2210 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002211 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002212}
2213
2214/**
2215 * xmlXPathCountFunction:
2216 * @ctxt: the XPath Parser context
2217 *
2218 * Implement the count() XPath function
2219 */
2220void
2221xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2222 xmlXPathObjectPtr cur;
2223
2224 CHECK_ARITY(1);
2225 CHECK_TYPE(XPATH_NODESET);
2226 cur = valuePop(ctxt);
2227
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002228 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002229 xmlXPathFreeObject(cur);
2230}
2231
2232/**
2233 * xmlXPathIdFunction:
2234 * @ctxt: the XPath Parser context
2235 *
2236 * Implement the id() XPath function
2237 * The id function selects elements by their unique ID
2238 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2239 * then the result is the union of the result of applying id to the
2240 * string value of each of the nodes in the argument node-set. When the
2241 * argument to id is of any other type, the argument is converted to a
2242 * string as if by a call to the string function; the string is split
2243 * into a whitespace-separated list of tokens (whitespace is any sequence
2244 * of characters matching the production S); the result is a node-set
2245 * containing the elements in the same document as the context node that
2246 * have a unique ID equal to any of the tokens in the list.
2247 */
2248void
2249xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002250 const xmlChar *tokens;
2251 const xmlChar *cur;
2252 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002253 xmlAttrPtr attr;
2254 xmlNodePtr elem = NULL;
2255 xmlXPathObjectPtr ret, obj;
2256
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002257 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002258 obj = valuePop(ctxt);
2259 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2260 if (obj->type == XPATH_NODESET) {
2261 TODO /* ID function in case of NodeSet */
2262 }
2263 if (obj->type != XPATH_STRING) {
2264 valuePush(ctxt, obj);
2265 xmlXPathStringFunction(ctxt, 1);
2266 obj = valuePop(ctxt);
2267 if (obj->type != XPATH_STRING) {
2268 xmlXPathFreeObject(obj);
2269 return;
2270 }
2271 }
2272 tokens = obj->stringval;
2273
2274 ret = xmlXPathNewNodeSet(NULL);
2275 valuePush(ctxt, ret);
2276 if (tokens == NULL) {
2277 xmlXPathFreeObject(obj);
2278 return;
2279 }
2280
2281 cur = tokens;
2282
2283 while (IS_BLANK(*cur)) cur++;
2284 while (*cur != 0) {
2285 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2286 (*cur == '.') || (*cur == '-') ||
2287 (*cur == '_') || (*cur == ':') ||
2288 (IS_COMBINING(*cur)) ||
2289 (IS_EXTENDER(*cur)))
2290 cur++;
2291
2292 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2293
2294 ID = xmlStrndup(tokens, cur - tokens);
2295 attr = xmlGetID(ctxt->context->doc, ID);
2296 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002297 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002298 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2299 }
2300 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002301 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002302
2303 while (IS_BLANK(*cur)) cur++;
2304 tokens = cur;
2305 }
2306 xmlXPathFreeObject(obj);
2307 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002308}
2309
2310/**
2311 * xmlXPathLocalPartFunction:
2312 * @ctxt: the XPath Parser context
2313 *
2314 * Implement the local-part() XPath function
2315 * The local-part function returns a string containing the local part
2316 * of the name of the node in the argument node-set that is first in
2317 * document order. If the node-set is empty or the first node has no
2318 * name, an empty string is returned. If the argument is omitted it
2319 * defaults to the context node.
2320 */
2321void
2322xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2323 xmlXPathObjectPtr cur;
2324
2325 CHECK_ARITY(1);
2326 CHECK_TYPE(XPATH_NODESET);
2327 cur = valuePop(ctxt);
2328
2329 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002330 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002331 } else {
2332 int i = 0; /* Should be first in document order !!!!! */
2333 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2334 }
2335 xmlXPathFreeObject(cur);
2336}
2337
2338/**
2339 * xmlXPathNamespaceFunction:
2340 * @ctxt: the XPath Parser context
2341 *
2342 * Implement the namespace() XPath function
2343 * The namespace function returns a string containing the namespace URI
2344 * of the expanded name of the node in the argument node-set that is
2345 * first in document order. If the node-set is empty, the first node has
2346 * no name, or the expanded name has no namespace URI, an empty string
2347 * is returned. If the argument is omitted it defaults to the context node.
2348 */
2349void
2350xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2351 xmlXPathObjectPtr cur;
2352
Daniel Veillardb96e6431999-08-29 21:02:19 +00002353 if (nargs == 0) {
2354 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2355 nargs = 1;
2356 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002357 CHECK_ARITY(1);
2358 CHECK_TYPE(XPATH_NODESET);
2359 cur = valuePop(ctxt);
2360
2361 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002362 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002363 } else {
2364 int i = 0; /* Should be first in document order !!!!! */
2365
2366 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002367 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002368 else
2369 valuePush(ctxt, xmlXPathNewString(
2370 cur->nodesetval->nodeTab[i]->ns->href));
2371 }
2372 xmlXPathFreeObject(cur);
2373}
2374
2375/**
2376 * xmlXPathNameFunction:
2377 * @ctxt: the XPath Parser context
2378 *
2379 * Implement the name() XPath function
2380 * The name function returns a string containing a QName representing
2381 * the name of the node in the argument node-set that is first in documenti
2382 * order. The QName must represent the name with respect to the namespace
2383 * declarations in effect on the node whose name is being represented.
2384 * Typically, this will be the form in which the name occurred in the XML
2385 * source. This need not be the case if there are namespace declarations
2386 * in effect on the node that associate multiple prefixes with the same
2387 * namespace. However, an implementation may include information about
2388 * the original prefix in its representation of nodes; in this case, an
2389 * implementation can ensure that the returned string is always the same
2390 * as the QName used in the XML source. If the argument it omitted it
2391 * defaults to the context node.
2392 * Libxml keep the original prefix so the "real qualified name" used is
2393 * returned.
2394 */
2395void
2396xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2397 xmlXPathObjectPtr cur;
2398
2399 CHECK_ARITY(1);
2400 CHECK_TYPE(XPATH_NODESET);
2401 cur = valuePop(ctxt);
2402
2403 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002404 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002405 } else {
2406 int i = 0; /* Should be first in document order !!!!! */
2407
2408 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2409 valuePush(ctxt, xmlXPathNewString(
2410 cur->nodesetval->nodeTab[i]->name));
2411
2412 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002413 char name[2000];
2414 sprintf(name, "%s:%s",
2415 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2416 (char *) cur->nodesetval->nodeTab[i]->name);
2417 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002418 }
2419 }
2420 xmlXPathFreeObject(cur);
2421}
2422
2423/**
2424 * xmlXPathStringFunction:
2425 * @ctxt: the XPath Parser context
2426 *
2427 * Implement the string() XPath function
2428 * he string function converts an object to a string as follows:
2429 * - A node-set is converted to a string by returning the value of
2430 * the node in the node-set that is first in document order.
2431 * If the node-set is empty, an empty string is returned.
2432 * - A number is converted to a string as follows
2433 * + NaN is converted to the string NaN
2434 * + positive zero is converted to the string 0
2435 * + negative zero is converted to the string 0
2436 * + positive infinity is converted to the string Infinity
2437 * + negative infinity is converted to the string -Infinity
2438 * + if the number is an integer, the number is represented in
2439 * decimal form as a Number with no decimal point and no leading
2440 * zeros, preceded by a minus sign (-) if the number is negative
2441 * + otherwise, the number is represented in decimal form as a
2442 * Number including a decimal point with at least one digit
2443 * before the decimal point and at least one digit after the
2444 * decimal point, preceded by a minus sign (-) if the number
2445 * is negative; there must be no leading zeros before the decimal
2446 * point apart possibly from the one required digit immediatelyi
2447 * before the decimal point; beyond the one required digit
2448 * after the decimal point there must be as many, but only as
2449 * many, more digits as are needed to uniquely distinguish the
2450 * number from all other IEEE 754 numeric values.
2451 * - The boolean false value is converted to the string false.
2452 * The boolean true value is converted to the string true.
2453 */
2454void
2455xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2456 xmlXPathObjectPtr cur;
2457
2458 CHECK_ARITY(1);
2459 cur = valuePop(ctxt);
2460 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2461 switch (cur->type) {
2462 case XPATH_NODESET:
2463 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002464 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002465 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002466 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002467 int i = 0; /* Should be first in document order !!!!! */
2468 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2469 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002470 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002471 }
2472 xmlXPathFreeObject(cur);
2473 return;
2474 case XPATH_STRING:
2475 valuePush(ctxt, cur);
2476 return;
2477 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002478 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2479 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002480 xmlXPathFreeObject(cur);
2481 return;
2482 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002483 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002484
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002485 if (isnan(cur->floatval))
2486 sprintf(buf, "NaN");
2487 else if (isinf(cur->floatval) > 0)
2488 sprintf(buf, "+Infinity");
2489 else if (isinf(cur->floatval) < 0)
2490 sprintf(buf, "-Infinity");
2491 else
2492 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002493 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002494 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002495 return;
2496 }
2497 }
2498 STRANGE
2499}
2500
2501/**
2502 * xmlXPathStringLengthFunction:
2503 * @ctxt: the XPath Parser context
2504 *
2505 * Implement the string-length() XPath function
2506 * The string-length returns the number of characters in the string
2507 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2508 * the context node converted to a string, in other words the value
2509 * of the context node.
2510 */
2511void
2512xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2513 xmlXPathObjectPtr cur;
2514
2515 if (nargs == 0) {
2516 if (ctxt->context->node == NULL) {
2517 valuePush(ctxt, xmlXPathNewFloat(0));
2518 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002519 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002520
2521 content = xmlNodeGetContent(ctxt->context->node);
2522 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002523 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002524 }
2525 return;
2526 }
2527 CHECK_ARITY(1);
2528 CHECK_TYPE(XPATH_STRING);
2529 cur = valuePop(ctxt);
2530 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2531 xmlXPathFreeObject(cur);
2532}
2533
2534/**
2535 * xmlXPathConcatFunction:
2536 * @ctxt: the XPath Parser context
2537 *
2538 * Implement the concat() XPath function
2539 * The concat function returns the concatenation of its arguments.
2540 */
2541void
2542xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2543 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002544 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002545
2546 if (nargs < 2) {
2547 CHECK_ARITY(2);
2548 }
2549
2550 cur = valuePop(ctxt);
2551 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2552 xmlXPathFreeObject(cur);
2553 return;
2554 }
2555 nargs--;
2556
2557 while (nargs > 0) {
2558 new = valuePop(ctxt);
2559 if ((new == NULL) || (new->type != XPATH_STRING)) {
2560 xmlXPathFreeObject(new);
2561 xmlXPathFreeObject(cur);
2562 ERROR(XPATH_INVALID_TYPE);
2563 }
2564 tmp = xmlStrcat(new->stringval, cur->stringval);
2565 new->stringval = cur->stringval;
2566 cur->stringval = tmp;
2567
2568 xmlXPathFreeObject(new);
2569 nargs--;
2570 }
2571 valuePush(ctxt, cur);
2572}
2573
2574/**
2575 * xmlXPathContainsFunction:
2576 * @ctxt: the XPath Parser context
2577 *
2578 * Implement the contains() XPath function
2579 * The contains function returns true if the first argument string
2580 * contains the second argument string, and otherwise returns false.
2581 */
2582void
2583xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2584 xmlXPathObjectPtr hay, needle;
2585
2586 CHECK_ARITY(2);
2587 CHECK_TYPE(XPATH_STRING);
2588 needle = valuePop(ctxt);
2589 hay = valuePop(ctxt);
2590 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2591 xmlXPathFreeObject(hay);
2592 xmlXPathFreeObject(needle);
2593 ERROR(XPATH_INVALID_TYPE);
2594 }
2595 if (xmlStrstr(hay->stringval, needle->stringval))
2596 valuePush(ctxt, xmlXPathNewBoolean(1));
2597 else
2598 valuePush(ctxt, xmlXPathNewBoolean(0));
2599 xmlXPathFreeObject(hay);
2600 xmlXPathFreeObject(needle);
2601}
2602
2603/**
2604 * xmlXPathStartsWithFunction:
2605 * @ctxt: the XPath Parser context
2606 *
2607 * Implement the starts-with() XPath function
2608 * The starts-with function returns true if the first argument string
2609 * starts with the second argument string, and otherwise returns false.
2610 */
2611void
2612xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2613 xmlXPathObjectPtr hay, needle;
2614 int n;
2615
2616 CHECK_ARITY(2);
2617 CHECK_TYPE(XPATH_STRING);
2618 needle = valuePop(ctxt);
2619 hay = valuePop(ctxt);
2620 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2621 xmlXPathFreeObject(hay);
2622 xmlXPathFreeObject(needle);
2623 ERROR(XPATH_INVALID_TYPE);
2624 }
2625 n = xmlStrlen(needle->stringval);
2626 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2627 valuePush(ctxt, xmlXPathNewBoolean(0));
2628 else
2629 valuePush(ctxt, xmlXPathNewBoolean(1));
2630 xmlXPathFreeObject(hay);
2631 xmlXPathFreeObject(needle);
2632}
2633
2634/**
2635 * xmlXPathSubstringFunction:
2636 * @ctxt: the XPath Parser context
2637 *
2638 * Implement the substring() XPath function
2639 * The substring function returns the substring of the first argument
2640 * starting at the position specified in the second argument with
2641 * length specified in the third argument. For example,
2642 * substring("12345",2,3) returns "234". If the third argument is not
2643 * specified, it returns the substring starting at the position specified
2644 * in the second argument and continuing to the end of the string. For
2645 * example, substring("12345",2) returns "2345". More precisely, each
2646 * character in the string (see [3.6 Strings]) is considered to have a
2647 * numeric position: the position of the first character is 1, the position
2648 * of the second character is 2 and so on. The returned substring contains
2649 * those characters for which the position of the character is greater than
2650 * or equal to the second argument and, if the third argument is specified,
2651 * less than the sum of the second and third arguments; the comparisons
2652 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2653 * - substring("12345", 1.5, 2.6) returns "234"
2654 * - substring("12345", 0, 3) returns "12"
2655 * - substring("12345", 0 div 0, 3) returns ""
2656 * - substring("12345", 1, 0 div 0) returns ""
2657 * - substring("12345", -42, 1 div 0) returns "12345"
2658 * - substring("12345", -1 div 0, 1 div 0) returns ""
2659 */
2660void
2661xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2662 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002663 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002664 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002665 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002666
2667 /*
2668 * Conformance needs to be checked !!!!!
2669 */
2670 if (nargs < 2) {
2671 CHECK_ARITY(2);
2672 }
2673 if (nargs > 3) {
2674 CHECK_ARITY(3);
2675 }
2676 if (nargs == 3) {
2677 CHECK_TYPE(XPATH_NUMBER);
2678 len = valuePop(ctxt);
2679 le = len->floatval;
2680 xmlXPathFreeObject(len);
2681 } else {
2682 le = 2000000000;
2683 }
2684 CHECK_TYPE(XPATH_NUMBER);
2685 start = valuePop(ctxt);
2686 in = start->floatval;
2687 xmlXPathFreeObject(start);
2688 CHECK_TYPE(XPATH_STRING);
2689 str = valuePop(ctxt);
2690 le += in;
2691
2692 /* integer index of the first char */
2693 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002694 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002695
2696 /* integer index of the last char */
2697 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002698 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002699
2700 /* back to a zero based len */
2701 i--;
2702 l--;
2703
2704 /* check against the string len */
2705 if (l > 1024) {
2706 l = xmlStrlen(str->stringval);
2707 }
2708 if (i < 0) {
2709 i = 0;
2710 }
2711
2712 /* number of chars to copy */
2713 l -= i;
2714
2715 ret = xmlStrsub(str->stringval, i, l);
2716 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002717 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002718 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002719 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002720 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002721 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002722 xmlXPathFreeObject(str);
2723}
2724
2725/**
2726 * xmlXPathSubstringBeforeFunction:
2727 * @ctxt: the XPath Parser context
2728 *
2729 * Implement the substring-before() XPath function
2730 * The substring-before function returns the substring of the first
2731 * argument string that precedes the first occurrence of the second
2732 * argument string in the first argument string, or the empty string
2733 * if the first argument string does not contain the second argument
2734 * string. For example, substring-before("1999/04/01","/") returns 1999.
2735 */
2736void
2737xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2738 CHECK_ARITY(2);
2739 TODO /* substring before */
2740}
2741
2742/**
2743 * xmlXPathSubstringAfterFunction:
2744 * @ctxt: the XPath Parser context
2745 *
2746 * Implement the substring-after() XPath function
2747 * The substring-after function returns the substring of the first
2748 * argument string that follows the first occurrence of the second
2749 * argument string in the first argument string, or the empty stringi
2750 * if the first argument string does not contain the second argument
2751 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2752 * and substring-after("1999/04/01","19") returns 99/04/01.
2753 */
2754void
2755xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2756 CHECK_ARITY(2);
2757 TODO /* substring after */
2758}
2759
2760/**
2761 * xmlXPathNormalizeFunction:
2762 * @ctxt: the XPath Parser context
2763 *
2764 * Implement the normalize() XPath function
2765 * The normalize function returns the argument string with white
2766 * space normalized by stripping leading and trailing whitespace
2767 * and replacing sequences of whitespace characters by a single
2768 * space. Whitespace characters are the same allowed by the S production
2769 * in XML. If the argument is omitted, it defaults to the context
2770 * node converted to a string, in other words the value of the context node.
2771 */
2772void
2773xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2774 CHECK_ARITY(1);
2775 TODO /* normalize isn't as boring as translate, but pretty much */
2776}
2777
2778/**
2779 * xmlXPathTranslateFunction:
2780 * @ctxt: the XPath Parser context
2781 *
2782 * Implement the translate() XPath function
2783 * The translate function returns the first argument string with
2784 * occurrences of characters in the second argument string replaced
2785 * by the character at the corresponding position in the third argument
2786 * string. For example, translate("bar","abc","ABC") returns the string
2787 * BAr. If there is a character in the second argument string with no
2788 * character at a corresponding position in the third argument string
2789 * (because the second argument string is longer than the third argument
2790 * string), then occurrences of that character in the first argument
2791 * string are removed. For example, translate("--aaa--","abc-","ABC")
2792 * returns "AAA". If a character occurs more than once in second
2793 * argument string, then the first occurrence determines the replacement
2794 * character. If the third argument string is longer than the second
2795 * argument string, then excess characters are ignored.
2796 */
2797void
2798xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2799 CHECK_ARITY(3);
2800 TODO /* translate is boring, waiting for UTF-8 representation too */
2801}
2802
2803/**
2804 * xmlXPathBooleanFunction:
2805 * @ctxt: the XPath Parser context
2806 *
2807 * Implement the boolean() XPath function
2808 * he boolean function converts its argument to a boolean as follows:
2809 * - a number is true if and only if it is neither positive or
2810 * negative zero nor NaN
2811 * - a node-set is true if and only if it is non-empty
2812 * - a string is true if and only if its length is non-zero
2813 */
2814void
2815xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2816 xmlXPathObjectPtr cur;
2817 int res = 0;
2818
2819 CHECK_ARITY(1);
2820 cur = valuePop(ctxt);
2821 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2822 switch (cur->type) {
2823 case XPATH_NODESET:
2824 if ((cur->nodesetval == NULL) ||
2825 (cur->nodesetval->nodeNr == 0)) res = 0;
2826 else
2827 res = 1;
2828 break;
2829 case XPATH_STRING:
2830 if ((cur->stringval == NULL) ||
2831 (cur->stringval[0] == 0)) res = 0;
2832 else
2833 res = 1;
2834 break;
2835 case XPATH_BOOLEAN:
2836 valuePush(ctxt, cur);
2837 return;
2838 case XPATH_NUMBER:
2839 if (cur->floatval) res = 1;
2840 break;
2841 default:
2842 STRANGE
2843 }
2844 xmlXPathFreeObject(cur);
2845 valuePush(ctxt, xmlXPathNewBoolean(res));
2846}
2847
2848/**
2849 * xmlXPathNotFunction:
2850 * @ctxt: the XPath Parser context
2851 *
2852 * Implement the not() XPath function
2853 * The not function returns true if its argument is false,
2854 * and false otherwise.
2855 */
2856void
2857xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2858 CHECK_ARITY(1);
2859 CHECK_TYPE(XPATH_BOOLEAN);
2860 ctxt->value->boolval = ! ctxt->value->boolval;
2861}
2862
2863/**
2864 * xmlXPathTrueFunction:
2865 * @ctxt: the XPath Parser context
2866 *
2867 * Implement the true() XPath function
2868 */
2869void
2870xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2871 CHECK_ARITY(0);
2872 valuePush(ctxt, xmlXPathNewBoolean(1));
2873}
2874
2875/**
2876 * xmlXPathFalseFunction:
2877 * @ctxt: the XPath Parser context
2878 *
2879 * Implement the false() XPath function
2880 */
2881void
2882xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2883 CHECK_ARITY(0);
2884 valuePush(ctxt, xmlXPathNewBoolean(0));
2885}
2886
2887/**
2888 * xmlXPathLangFunction:
2889 * @ctxt: the XPath Parser context
2890 *
2891 * Implement the lang() XPath function
2892 * The lang function returns true or false depending on whether the
2893 * language of the context node as specified by xml:lang attributes
2894 * is the same as or is a sublanguage of the language specified by
2895 * the argument string. The language of the context node is determined
2896 * by the value of the xml:lang attribute on the context node, or, if
2897 * the context node has no xml:lang attribute, by the value of the
2898 * xml:lang attribute on the nearest ancestor of the context node that
2899 * has an xml:lang attribute. If there is no such attribute, then lang
2900 * returns false. If there is such an attribute, then lang returns
2901 * true if the attribute value is equal to the argument ignoring case,
2902 * or if there is some suffix starting with - such that the attribute
2903 * value is equal to the argument ignoring that suffix of the attribute
2904 * value and ignoring case.
2905 */
2906void
2907xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002908 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002909 const xmlChar *theLang;
2910 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002911 int ret = 0;
2912 int i;
2913
2914 CHECK_ARITY(1);
2915 CHECK_TYPE(XPATH_STRING);
2916 val = valuePop(ctxt);
2917 lang = val->stringval;
2918 theLang = xmlNodeGetLang(ctxt->context->node);
2919 if ((theLang != NULL) && (lang != NULL)) {
2920 for (i = 0;lang[i] != 0;i++)
2921 if (toupper(lang[i]) != toupper(theLang[i]))
2922 goto not_equal;
2923 ret = 1;
2924 }
2925not_equal:
2926 xmlXPathFreeObject(val);
2927 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002928}
2929
2930/**
2931 * xmlXPathNumberFunction:
2932 * @ctxt: the XPath Parser context
2933 *
2934 * Implement the number() XPath function
2935 */
2936void
2937xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2938 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002939 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002940
2941 CHECK_ARITY(1);
2942 cur = valuePop(ctxt);
2943 switch (cur->type) {
2944 case XPATH_NODESET:
2945 valuePush(ctxt, cur);
2946 xmlXPathStringFunction(ctxt, 1);
2947 cur = valuePop(ctxt);
2948 case XPATH_STRING:
2949 res = xmlXPathStringEvalNumber(cur->stringval);
2950 valuePush(ctxt, xmlXPathNewFloat(res));
2951 xmlXPathFreeObject(cur);
2952 return;
2953 case XPATH_BOOLEAN:
2954 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2955 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2956 xmlXPathFreeObject(cur);
2957 return;
2958 case XPATH_NUMBER:
2959 valuePush(ctxt, cur);
2960 return;
2961 }
2962 STRANGE
2963}
2964
2965/**
2966 * xmlXPathSumFunction:
2967 * @ctxt: the XPath Parser context
2968 *
2969 * Implement the sum() XPath function
2970 * The sum function returns the sum of the values of the nodes in
2971 * the argument node-set.
2972 */
2973void
2974xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2975 CHECK_ARITY(1);
2976 TODO /* BUG Sum : don't understand the definition */
2977}
2978
2979/**
2980 * xmlXPathFloorFunction:
2981 * @ctxt: the XPath Parser context
2982 *
2983 * Implement the floor() XPath function
2984 * The floor function returns the largest (closest to positive infinity)
2985 * number that is not greater than the argument and that is an integer.
2986 */
2987void
2988xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2989 CHECK_ARITY(1);
2990 CHECK_TYPE(XPATH_NUMBER);
2991 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002992 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002993}
2994
2995/**
2996 * xmlXPathCeilingFunction:
2997 * @ctxt: the XPath Parser context
2998 *
2999 * Implement the ceiling() XPath function
3000 * The ceiling function returns the smallest (closest to negative infinity)
3001 * number that is not less than the argument and that is an integer.
3002 */
3003void
3004xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003005 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003006
3007 CHECK_ARITY(1);
3008 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003009 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003010 if (f != ctxt->value->floatval)
3011 ctxt->value->floatval = f + 1;
3012}
3013
3014/**
3015 * xmlXPathRoundFunction:
3016 * @ctxt: the XPath Parser context
3017 *
3018 * Implement the round() XPath function
3019 * The round function returns the number that is closest to the
3020 * argument and that is an integer. If there are two such numbers,
3021 * then the one that is even is returned.
3022 */
3023void
3024xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003025 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003026
3027 CHECK_ARITY(1);
3028 CHECK_TYPE(XPATH_NUMBER);
3029 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003030 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003031 if (ctxt->value->floatval < f + 0.5)
3032 ctxt->value->floatval = f;
3033 else if (ctxt->value->floatval == f + 0.5)
3034 ctxt->value->floatval = f; /* !!!! Not following the spec here */
3035 else
3036 ctxt->value->floatval = f + 1;
3037}
3038
3039/************************************************************************
3040 * *
3041 * The Parser *
3042 * *
3043 ************************************************************************/
3044
3045/*
3046 * a couple of forward declarations since we use a recursive call based
3047 * implementation.
3048 */
3049void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3050void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3051void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3052void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3053
3054/**
3055 * xmlXPathParseNCName:
3056 * @ctxt: the XPath Parser context
3057 *
3058 * parse an XML namespace non qualified name.
3059 *
3060 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3061 *
3062 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3063 * CombiningChar | Extender
3064 *
3065 * Returns the namespace name or NULL
3066 */
3067
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003068xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003069xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003070 const xmlChar *q;
3071 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003072
3073 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3074 q = NEXT;
3075
3076 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3077 (CUR == '.') || (CUR == '-') ||
3078 (CUR == '_') ||
3079 (IS_COMBINING(CUR)) ||
3080 (IS_EXTENDER(CUR)))
3081 NEXT;
3082
3083 ret = xmlStrndup(q, CUR_PTR - q);
3084
3085 return(ret);
3086}
3087
3088/**
3089 * xmlXPathParseQName:
3090 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003091 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003092 *
3093 * parse an XML qualified name
3094 *
3095 * [NS 5] QName ::= (Prefix ':')? LocalPart
3096 *
3097 * [NS 6] Prefix ::= NCName
3098 *
3099 * [NS 7] LocalPart ::= NCName
3100 *
3101 * Returns the function returns the local part, and prefix is updated
3102 * to get the Prefix if any.
3103 */
3104
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003105xmlChar *
3106xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3107 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003108
3109 *prefix = NULL;
3110 ret = xmlXPathParseNCName(ctxt);
3111 if (CUR == ':') {
3112 *prefix = ret;
3113 NEXT;
3114 ret = xmlXPathParseNCName(ctxt);
3115 }
3116 return(ret);
3117}
3118
3119/**
3120 * xmlXPathStringEvalNumber:
3121 * @str: A string to scan
3122 *
3123 * [30] Number ::= Digits ('.' Digits)?
3124 * | '.' Digits
3125 * [31] Digits ::= [0-9]+
3126 *
3127 * Parse and evaluate a Number in the string
3128 *
3129 * BUG: "1.' is not valid ... James promised correction
3130 * as Digits ('.' Digits?)?
3131 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003132 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003133 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003134double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003135xmlXPathStringEvalNumber(const xmlChar *str) {
3136 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003137 double ret = 0.0;
3138 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003139 int ok = 0;
3140
3141 while (*cur == ' ') cur++;
3142 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003143 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003144 }
3145 while ((*cur >= '0') && (*cur <= '9')) {
3146 ret = ret * 10 + (*cur - '0');
3147 ok = 1;
3148 cur++;
3149 }
3150 if (*cur == '.') {
3151 cur++;
3152 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003153 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003154 }
3155 while ((*cur >= '0') && (*cur <= '9')) {
3156 mult /= 10;
3157 ret = ret + (*cur - '0') * mult;
3158 cur++;
3159 }
3160 }
3161 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003162 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003163 return(ret);
3164}
3165
3166/**
3167 * xmlXPathEvalNumber:
3168 * @ctxt: the XPath Parser context
3169 *
3170 * [30] Number ::= Digits ('.' Digits)?
3171 * | '.' Digits
3172 * [31] Digits ::= [0-9]+
3173 *
3174 * Parse and evaluate a Number, then push it on the stack
3175 *
3176 * BUG: "1.' is not valid ... James promised correction
3177 * as Digits ('.' Digits?)?
3178 */
3179void
3180xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003181 double ret = 0.0;
3182 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003183 int ok = 0;
3184
3185 CHECK_ERROR;
3186 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3187 ERROR(XPATH_NUMBER_ERROR);
3188 }
3189 while ((CUR >= '0') && (CUR <= '9')) {
3190 ret = ret * 10 + (CUR - '0');
3191 ok = 1;
3192 NEXT;
3193 }
3194 if (CUR == '.') {
3195 NEXT;
3196 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3197 ERROR(XPATH_NUMBER_ERROR);
3198 }
3199 while ((CUR >= '0') && (CUR <= '9')) {
3200 mult /= 10;
3201 ret = ret + (CUR - '0') * mult;
3202 NEXT;
3203 }
3204 }
3205 valuePush(ctxt, xmlXPathNewFloat(ret));
3206}
3207
3208/**
3209 * xmlXPathEvalLiteral:
3210 * @ctxt: the XPath Parser context
3211 *
3212 * Parse a Literal and push it on the stack.
3213 *
3214 * [29] Literal ::= '"' [^"]* '"'
3215 * | "'" [^']* "'"
3216 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003217 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003218 */
3219void
3220xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003221 const xmlChar *q;
3222 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003223
3224 if (CUR == '"') {
3225 NEXT;
3226 q = CUR_PTR;
3227 while ((IS_CHAR(CUR)) && (CUR != '"'))
3228 NEXT;
3229 if (!IS_CHAR(CUR)) {
3230 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3231 } else {
3232 ret = xmlStrndup(q, CUR_PTR - q);
3233 NEXT;
3234 }
3235 } else if (CUR == '\'') {
3236 NEXT;
3237 q = CUR_PTR;
3238 while ((IS_CHAR(CUR)) && (CUR != '\''))
3239 NEXT;
3240 if (!IS_CHAR(CUR)) {
3241 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3242 } else {
3243 ret = xmlStrndup(q, CUR_PTR - q);
3244 NEXT;
3245 }
3246 } else {
3247 ERROR(XPATH_START_LITERAL_ERROR);
3248 }
3249 if (ret == NULL) return;
3250 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003251 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003252}
3253
3254/**
3255 * xmlXPathEvalVariableReference:
3256 * @ctxt: the XPath Parser context
3257 *
3258 * Parse a VariableReference, evaluate it and push it on the stack.
3259 *
3260 * The variable bindings consist of a mapping from variable names
3261 * to variable values. The value of a variable is an object, which
3262 * of any of the types that are possible for the value of an expression,
3263 * and may also be of additional types not specified here.
3264 *
3265 * Early evaluation is possible since:
3266 * The variable bindings [...] used to evaluate a subexpression are
3267 * always the same as those used to evaluate the containing expression.
3268 *
3269 * [36] VariableReference ::= '$' QName
3270 */
3271void
3272xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003273 xmlChar *name;
3274 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003275 xmlXPathObjectPtr value;
3276
3277 if (CUR != '$') {
3278 ERROR(XPATH_VARIABLE_REF_ERROR);
3279 }
3280 name = xmlXPathParseQName(ctxt, &prefix);
3281 if (name == NULL) {
3282 ERROR(XPATH_VARIABLE_REF_ERROR);
3283 }
3284 value = xmlXPathVariablelookup(ctxt, prefix, name);
3285 if (value == NULL) {
3286 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3287 }
3288 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003289 if (prefix != NULL) xmlFree(prefix);
3290 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003291}
3292
3293
3294/**
3295 * xmlXPathFunctionLookup:
3296 * @ctxt: the XPath Parser context
3297 * @name: a name string
3298 *
3299 * Search for a function of the given name
3300 *
3301 * [35] FunctionName ::= QName - NodeType
3302 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003303 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003304 *
3305 * Returns the xmlXPathFunction if found, or NULL otherwise
3306 */
3307xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003308xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003309 switch (name[0]) {
3310 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003311 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003312 return(xmlXPathBooleanFunction);
3313 break;
3314 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003315 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003316 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003317 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003318 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003319 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003320 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003321 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003322 return(xmlXPathContainsFunction);
3323 break;
3324 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003325 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003326 return(xmlXPathIdFunction);
3327 break;
3328 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003329 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003330 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003331 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003332 return(xmlXPathFloorFunction);
3333 break;
3334 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003335 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003336 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003337 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003338 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003339 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003340 return(xmlXPathLocalPartFunction);
3341 break;
3342 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003343 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003344 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003345 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003347 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003348 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003349 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3350 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003351 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003352 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003353 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003354 return(xmlXPathNumberFunction);
3355 break;
3356 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003357 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003358 return(xmlXPathPositionFunction);
3359 break;
3360 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003361 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003362 return(xmlXPathRoundFunction);
3363 break;
3364 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003365 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003366 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003367 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003368 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003369 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003370 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003371 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003372 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003373 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003374 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003375 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003376 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003377 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003378 return(xmlXPathSumFunction);
3379 break;
3380 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003381 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003382 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003383 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003384 return(xmlXPathTranslateFunction);
3385 break;
3386 }
3387 return(NULL);
3388}
3389
3390/**
3391 * xmlXPathEvalLocationPathName:
3392 * @ctxt: the XPath Parser context
3393 * @name: a name string
3394 *
3395 * Various names in the beginning of a LocationPath expression
3396 * indicate whether that's an Axis, a node type,
3397 *
3398 * [6] AxisName ::= 'ancestor'
3399 * | 'ancestor-or-self'
3400 * | 'attribute'
3401 * | 'child'
3402 * | 'descendant'
3403 * | 'descendant-or-self'
3404 * | 'following'
3405 * | 'following-sibling'
3406 * | 'namespace'
3407 * | 'parent'
3408 * | 'preceding'
3409 * | 'preceding-sibling'
3410 * | 'self'
3411 * [38] NodeType ::= 'comment'
3412 * | 'text'
3413 * | 'processing-instruction'
3414 * | 'node'
3415 */
3416int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003417xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003418 switch (name[0]) {
3419 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003420 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3421 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3422 return(AXIS_ANCESTOR_OR_SELF);
3423 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003424 break;
3425 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003426 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3427 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003428 break;
3429 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003430 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3431 return(AXIS_DESCENDANT);
3432 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3433 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003434 break;
3435 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003436 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3437 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3438 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003439 break;
3440 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003441 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3442 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003443 break;
3444 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003445 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3446 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3447 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3448 return(AXIS_PRECEDING_SIBLING);
3449 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3450 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003451 break;
3452 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003453 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003454 break;
3455 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003456 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003457 break;
3458 }
3459 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3460 return(0);
3461}
3462
3463/**
3464 * xmlXPathEvalFunctionCall:
3465 * @ctxt: the XPath Parser context
3466 *
3467 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3468 * [17] Argument ::= Expr
3469 *
3470 * Parse and evaluate a function call, the evaluation of all arguments are
3471 * pushed on the stack
3472 */
3473void
3474xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003475 xmlChar *name;
3476 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003477 xmlXPathFunction func;
3478 int nbargs = 0;
3479
3480 name = xmlXPathParseQName(ctxt, &prefix);
3481 if (name == NULL) {
3482 ERROR(XPATH_EXPR_ERROR);
3483 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003484 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003485 func = xmlXPathIsFunction(ctxt, name);
3486 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003487 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003488 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3489 }
3490#ifdef DEBUG_EXPR
3491 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3492#endif
3493
3494 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003495 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003496 ERROR(XPATH_EXPR_ERROR);
3497 }
3498 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003499 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003500
3501 while (CUR != ')') {
3502 xmlXPathEvalExpr(ctxt);
3503 nbargs++;
3504 if (CUR == ')') break;
3505 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003506 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003507 ERROR(XPATH_EXPR_ERROR);
3508 }
3509 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003510 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003511 }
3512 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003513 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003514 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003515 func(ctxt, nbargs);
3516}
3517
3518/**
3519 * xmlXPathEvalPrimaryExpr:
3520 * @ctxt: the XPath Parser context
3521 *
3522 * [15] PrimaryExpr ::= VariableReference
3523 * | '(' Expr ')'
3524 * | Literal
3525 * | Number
3526 * | FunctionCall
3527 *
3528 * Parse and evaluate a primary expression, then push the result on the stack
3529 */
3530void
3531xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003532 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003533 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3534 else if (CUR == '(') {
3535 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003536 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003537 xmlXPathEvalExpr(ctxt);
3538 if (CUR != ')') {
3539 ERROR(XPATH_EXPR_ERROR);
3540 }
3541 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003542 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003543 } else if (IS_DIGIT(CUR)) {
3544 xmlXPathEvalNumber(ctxt);
3545 } else if ((CUR == '\'') || (CUR == '"')) {
3546 xmlXPathEvalLiteral(ctxt);
3547 } else {
3548 xmlXPathEvalFunctionCall(ctxt);
3549 }
3550}
3551
3552/**
3553 * xmlXPathEvalFilterExpr:
3554 * @ctxt: the XPath Parser context
3555 *
3556 * [20] FilterExpr ::= PrimaryExpr
3557 * | FilterExpr Predicate
3558 *
3559 * Parse and evaluate a filter expression, then push the result on the stack
3560 * Square brackets are used to filter expressions in the same way that
3561 * they are used in location paths. It is an error if the expression to
3562 * be filtered does not evaluate to a node-set. The context node list
3563 * used for evaluating the expression in square brackets is the node-set
3564 * to be filtered listed in document order.
3565 */
3566
3567void
3568xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3569 /****
3570 xmlNodeSetPtr oldset = NULL;
3571 xmlXPathObjectPtr arg;
3572 ****/
3573
3574 xmlXPathEvalPrimaryExpr(ctxt);
3575 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003576 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003577
3578 if (CUR != '[') return;
3579
3580 CHECK_TYPE(XPATH_NODESET);
3581
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003582 while (CUR == '[') {
3583 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003584 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003585 }
3586
3587
3588}
3589
3590/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003591 * xmlXPathScanName:
3592 * @ctxt: the XPath Parser context
3593 *
3594 * Trickery: parse an XML name but without consuming the input flow
3595 * Needed for rollback cases.
3596 *
3597 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3598 * CombiningChar | Extender
3599 *
3600 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3601 *
3602 * [6] Names ::= Name (S Name)*
3603 *
3604 * Returns the Name parsed or NULL
3605 */
3606
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003607xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003608xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003609 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003610 int len = 0;
3611
Daniel Veillard00fdf371999-10-08 09:40:39 +00003612 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003613 if (!IS_LETTER(CUR) && (CUR != '_') &&
3614 (CUR != ':')) {
3615 return(NULL);
3616 }
3617
3618 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3619 (NXT(len) == '.') || (NXT(len) == '-') ||
3620 (NXT(len) == '_') || (NXT(len) == ':') ||
3621 (IS_COMBINING(NXT(len))) ||
3622 (IS_EXTENDER(NXT(len)))) {
3623 buf[len] = NXT(len);
3624 len++;
3625 if (len >= XML_MAX_NAMELEN) {
3626 fprintf(stderr,
3627 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3628 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3629 (NXT(len) == '.') || (NXT(len) == '-') ||
3630 (NXT(len) == '_') || (NXT(len) == ':') ||
3631 (IS_COMBINING(NXT(len))) ||
3632 (IS_EXTENDER(NXT(len))))
3633 len++;
3634 break;
3635 }
3636 }
3637 return(xmlStrndup(buf, len));
3638}
3639
3640/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003641 * xmlXPathEvalPathExpr:
3642 * @ctxt: the XPath Parser context
3643 *
3644 * [19] PathExpr ::= LocationPath
3645 * | FilterExpr
3646 * | FilterExpr '/' RelativeLocationPath
3647 * | FilterExpr '//' RelativeLocationPath
3648 *
3649 * Parse and evaluate a path expression, then push the result on the stack
3650 * The / operator and // operators combine an arbitrary expression
3651 * and a relative location path. It is an error if the expression
3652 * does not evaluate to a node-set.
3653 * The / operator does composition in the same way as when / is
3654 * used in a location path. As in location paths, // is short for
3655 * /descendant-or-self::node()/.
3656 */
3657
3658void
3659xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3660 xmlNodeSetPtr newset = NULL;
3661
Daniel Veillard00fdf371999-10-08 09:40:39 +00003662 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003663 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3664 (CUR == '\'') || (CUR == '"')) {
3665 xmlXPathEvalFilterExpr(ctxt);
3666 CHECK_ERROR;
3667 if ((CUR == '/') && (NXT(1) == '/')) {
3668 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003669 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003670 if (ctxt->context->nodelist == NULL) {
3671 STRANGE
3672 xmlXPathRoot(ctxt);
3673 }
3674 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3675 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3676 if (ctxt->context->nodelist != NULL)
3677 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3678 ctxt->context->nodelist = newset;
3679 ctxt->context->node = NULL;
3680 xmlXPathEvalRelativeLocationPath(ctxt);
3681 } else if (CUR == '/') {
3682 xmlXPathEvalRelativeLocationPath(ctxt);
3683 }
3684 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003685 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003686 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003687
3688 name = xmlXPathScanName(ctxt);
3689 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3690 xmlXPathEvalLocationPath(ctxt);
3691 else
3692 xmlXPathEvalFilterExpr(ctxt);
3693 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003694 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003695 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003696 if (ctxt->context->nodelist != NULL)
3697 valuePush(ctxt, xmlXPathNewNodeSetList(ctxt->context->nodelist));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003698}
3699
3700/**
3701 * xmlXPathEvalUnionExpr:
3702 * @ctxt: the XPath Parser context
3703 *
3704 * [18] UnionExpr ::= PathExpr
3705 * | UnionExpr '|' PathExpr
3706 *
3707 * Parse and evaluate an union expression, then push the result on the stack
3708 */
3709
3710void
3711xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3712 xmlXPathEvalPathExpr(ctxt);
3713 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003714 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003715 if (CUR == '|') {
3716 xmlNodeSetPtr old = ctxt->context->nodelist;
3717
Daniel Veillard00fdf371999-10-08 09:40:39 +00003718 NEXT;
3719 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003720 xmlXPathEvalPathExpr(ctxt);
3721
3722 if (ctxt->context->nodelist == NULL)
3723 ctxt->context->nodelist = old;
3724 else {
3725 ctxt->context->nodelist =
3726 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3727 xmlXPathFreeNodeSet(old);
3728 }
3729 }
3730}
3731
3732/**
3733 * xmlXPathEvalUnaryExpr:
3734 * @ctxt: the XPath Parser context
3735 *
3736 * [27] UnaryExpr ::= UnionExpr
3737 * | '-' UnaryExpr
3738 *
3739 * Parse and evaluate an unary expression, then push the result on the stack
3740 */
3741
3742void
3743xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3744 int minus = 0;
3745
Daniel Veillard00fdf371999-10-08 09:40:39 +00003746 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003747 if (CUR == '-') {
3748 minus = 1;
3749 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003750 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003751 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003752 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003753 CHECK_ERROR;
3754 if (minus) {
3755 xmlXPathValueFlipSign(ctxt);
3756 }
3757}
3758
3759/**
3760 * xmlXPathEvalMultiplicativeExpr:
3761 * @ctxt: the XPath Parser context
3762 *
3763 * [26] MultiplicativeExpr ::= UnaryExpr
3764 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3765 * | MultiplicativeExpr 'div' UnaryExpr
3766 * | MultiplicativeExpr 'mod' UnaryExpr
3767 * [34] MultiplyOperator ::= '*'
3768 *
3769 * Parse and evaluate an Additive expression, then push the result on the stack
3770 */
3771
3772void
3773xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3774 xmlXPathEvalUnaryExpr(ctxt);
3775 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003776 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003777 while ((CUR == '*') ||
3778 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3779 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3780 int op = -1;
3781
3782 if (CUR == '*') {
3783 op = 0;
3784 NEXT;
3785 } else if (CUR == 'd') {
3786 op = 1;
3787 SKIP(3);
3788 } else if (CUR == 'm') {
3789 op = 2;
3790 SKIP(3);
3791 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003792 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003793 xmlXPathEvalUnaryExpr(ctxt);
3794 CHECK_ERROR;
3795 switch (op) {
3796 case 0:
3797 xmlXPathMultValues(ctxt);
3798 break;
3799 case 1:
3800 xmlXPathDivValues(ctxt);
3801 break;
3802 case 2:
3803 xmlXPathModValues(ctxt);
3804 break;
3805 }
3806 }
3807}
3808
3809/**
3810 * xmlXPathEvalAdditiveExpr:
3811 * @ctxt: the XPath Parser context
3812 *
3813 * [25] AdditiveExpr ::= MultiplicativeExpr
3814 * | AdditiveExpr '+' MultiplicativeExpr
3815 * | AdditiveExpr '-' MultiplicativeExpr
3816 *
3817 * Parse and evaluate an Additive expression, then push the result on the stack
3818 */
3819
3820void
3821xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3822 xmlXPathEvalMultiplicativeExpr(ctxt);
3823 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003824 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003825 while ((CUR == '+') || (CUR == '-')) {
3826 int plus;
3827
3828 if (CUR == '+') plus = 1;
3829 else plus = 0;
3830 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003831 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003832 xmlXPathEvalMultiplicativeExpr(ctxt);
3833 CHECK_ERROR;
3834 if (plus) xmlXPathAddValues(ctxt);
3835 else xmlXPathSubValues(ctxt);
3836 }
3837}
3838
3839/**
3840 * xmlXPathEvalRelationalExpr:
3841 * @ctxt: the XPath Parser context
3842 *
3843 * [24] RelationalExpr ::= AdditiveExpr
3844 * | RelationalExpr '<' AdditiveExpr
3845 * | RelationalExpr '>' AdditiveExpr
3846 * | RelationalExpr '<=' AdditiveExpr
3847 * | RelationalExpr '>=' AdditiveExpr
3848 *
3849 * A <= B > C is allowed ? Answer from James, yes with
3850 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3851 * which is basically what got implemented.
3852 *
3853 * Parse and evaluate a Relational expression, then push the result
3854 * on the stack
3855 */
3856
3857void
3858xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3859 xmlXPathEvalAdditiveExpr(ctxt);
3860 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003861 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003862 while ((CUR == '<') ||
3863 (CUR == '>') ||
3864 ((CUR == '<') && (NXT(1) == '=')) ||
3865 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003866 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003867
3868 if (CUR == '<') inf = 1;
3869 else inf = 0;
3870 if (NXT(1) == '=') strict = 0;
3871 else strict = 1;
3872 NEXT;
3873 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003874 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003875 xmlXPathEvalAdditiveExpr(ctxt);
3876 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003877 ret = xmlXPathCompareValues(ctxt, inf, strict);
3878 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003879 }
3880}
3881
3882/**
3883 * xmlXPathEvalEqualityExpr:
3884 * @ctxt: the XPath Parser context
3885 *
3886 * [23] EqualityExpr ::= RelationalExpr
3887 * | EqualityExpr '=' RelationalExpr
3888 * | EqualityExpr '!=' RelationalExpr
3889 *
3890 * A != B != C is allowed ? Answer from James, yes with
3891 * (RelationalExpr = RelationalExpr) = RelationalExpr
3892 * (RelationalExpr != RelationalExpr) != RelationalExpr
3893 * which is basically what got implemented.
3894 *
3895 * Parse and evaluate an Equality expression, then push the result on the stack
3896 *
3897 */
3898void
3899xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3900 xmlXPathEvalRelationalExpr(ctxt);
3901 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003902 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003903 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003904 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003905 int eq, equal;
3906
3907 if (CUR == '=') eq = 1;
3908 else eq = 0;
3909 NEXT;
3910 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003911 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003912 xmlXPathEvalRelationalExpr(ctxt);
3913 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003914 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003915 if (eq) res = xmlXPathNewBoolean(equal);
3916 else res = xmlXPathNewBoolean(!equal);
3917 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003918 }
3919}
3920
3921/**
3922 * xmlXPathEvalAndExpr:
3923 * @ctxt: the XPath Parser context
3924 *
3925 * [22] AndExpr ::= EqualityExpr
3926 * | AndExpr 'and' EqualityExpr
3927 *
3928 * Parse and evaluate an AND expression, then push the result on the stack
3929 *
3930 */
3931void
3932xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3933 xmlXPathEvalEqualityExpr(ctxt);
3934 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003935 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003936 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3937 xmlXPathObjectPtr arg1, arg2;
3938
3939 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003940 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003941 xmlXPathEvalEqualityExpr(ctxt);
3942 CHECK_ERROR;
3943 arg2 = valuePop(ctxt);
3944 arg1 = valuePop(ctxt);
3945 arg1->boolval &= arg2->boolval;
3946 valuePush(ctxt, arg1);
3947 xmlXPathFreeObject(arg2);
3948 }
3949}
3950
3951/**
3952 * xmlXPathEvalExpr:
3953 * @ctxt: the XPath Parser context
3954 *
3955 * [14] Expr ::= OrExpr
3956 * [21] OrExpr ::= AndExpr
3957 * | OrExpr 'or' AndExpr
3958 *
3959 * Parse and evaluate an expression, then push the result on the stack
3960 *
3961 */
3962void
3963xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3964 xmlXPathEvalAndExpr(ctxt);
3965 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003966 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003967 while ((CUR == 'o') && (NXT(1) == 'r')) {
3968 xmlXPathObjectPtr arg1, arg2;
3969
3970 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003971 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003972 xmlXPathEvalAndExpr(ctxt);
3973 CHECK_ERROR;
3974 arg2 = valuePop(ctxt);
3975 arg1 = valuePop(ctxt);
3976 arg1->boolval |= arg2->boolval;
3977 valuePush(ctxt, arg1);
3978 xmlXPathFreeObject(arg2);
3979 }
3980}
3981
3982/**
3983 * xmlXPathEvaluatePredicateResult:
3984 * @ctxt: the XPath Parser context
3985 * @res: the Predicate Expression evaluation result
3986 * @index: index of the current node in the current list
3987 *
3988 * Evaluate a predicate result for the current node.
3989 * A PredicateExpr is evaluated by evaluating the Expr and converting
3990 * the result to a boolean. If the result is a number, the result will
3991 * be converted to true if the number is equal to the position of the
3992 * context node in the context node list (as returned by the position
3993 * function) and will be converted to false otherwise; if the result
3994 * is not a number, then the result will be converted as if by a call
3995 * to the boolean function.
3996 */
3997int
3998xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3999 xmlXPathObjectPtr res, int index) {
4000 if (res == NULL) return(0);
4001 switch (res->type) {
4002 case XPATH_BOOLEAN:
4003 return(res->boolval);
4004 case XPATH_NUMBER:
4005 return(res->floatval == index);
4006 case XPATH_NODESET:
4007 return(res->nodesetval->nodeNr != 0);
4008 case XPATH_STRING:
4009 return((res->stringval != NULL) &&
4010 (xmlStrlen(res->stringval) != 0));
4011 default:
4012 STRANGE
4013 }
4014 return(0);
4015}
4016
4017/**
4018 * xmlXPathEvalPredicate:
4019 * @ctxt: the XPath Parser context
4020 *
4021 * [8] Predicate ::= '[' PredicateExpr ']'
4022 * [9] PredicateExpr ::= Expr
4023 *
4024 * Parse and evaluate a predicate for all the elements of the
4025 * current node list. Then refine the list by removing all
4026 * nodes where the predicate is false.
4027 */
4028void
4029xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004030 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004031 xmlXPathObjectPtr res;
4032 xmlNodeSetPtr newset = NULL;
4033 int i;
4034
Daniel Veillard00fdf371999-10-08 09:40:39 +00004035 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004036 if (CUR != '[') {
4037 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4038 }
4039 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004040 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004041 if ((ctxt->context->nodelist == NULL) ||
4042 (ctxt->context->nodelist->nodeNr == 0)) {
4043 ctxt->context->node = NULL;
4044 xmlXPathEvalExpr(ctxt);
4045 CHECK_ERROR;
4046 res = valuePop(ctxt);
4047 if (res != NULL)
4048 xmlXPathFreeObject(res);
4049 } else {
4050 cur = ctxt->cur;
4051 newset = xmlXPathNodeSetCreate(NULL);
4052 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
4053 ctxt->cur = cur;
4054 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
4055 xmlXPathEvalExpr(ctxt);
4056 CHECK_ERROR;
4057 res = valuePop(ctxt);
4058 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
4059 xmlXPathNodeSetAdd(newset,
4060 ctxt->context->nodelist->nodeTab[i]);
4061 if (res != NULL)
4062 xmlXPathFreeObject(res);
4063 }
4064 if (ctxt->context->nodelist != NULL)
4065 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4066 ctxt->context->nodelist = newset;
4067 ctxt->context->node = NULL;
4068 }
4069 if (CUR != ']') {
4070 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4071 }
4072 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004073 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004074#ifdef DEBUG_STEP
4075 fprintf(xmlXPathDebug, "After predicate : ");
4076 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4077#endif
4078}
4079
4080/**
4081 * xmlXPathEvalBasis:
4082 * @ctxt: the XPath Parser context
4083 *
4084 * [5] Basis ::= AxisName '::' NodeTest
4085 * | AbbreviatedBasis
4086 * [13] AbbreviatedBasis ::= NodeTest
4087 * | '@' NodeTest
4088 * [7] NodeTest ::= WildcardName
4089 * | NodeType '(' ')'
4090 * | 'processing-instruction' '(' Literal ')'
4091 * [37] WildcardName ::= '*'
4092 * | NCName ':' '*'
4093 * | QName
4094 *
4095 * Evaluate one step in a Location Path
4096 */
4097void
4098xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004099 xmlChar *name = NULL;
4100 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004101 int type = 0;
4102 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4103 int nodetest = NODE_TEST_NONE;
4104 int nodetype = 0;
4105 xmlNodeSetPtr newset = NULL;
4106
4107 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004108 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004109 axis = AXIS_ATTRIBUTE;
4110 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004111 } else if (CUR == '*') {
4112 NEXT;
4113 nodetest = NODE_TEST_ALL;
4114 } else {
4115 name = xmlXPathParseNCName(ctxt);
4116 if (name == NULL) {
4117 ERROR(XPATH_EXPR_ERROR);
4118 }
4119 type = xmlXPathGetNameType(ctxt, name);
4120 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004121 case IS_FUNCTION: {
4122 xmlXPathFunction func;
4123 int nbargs = 0;
4124 xmlXPathObjectPtr top;
4125
4126 top = ctxt->value;
4127 func = xmlXPathIsFunction(ctxt, name);
4128 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004129 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004130 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4131 }
4132#ifdef DEBUG_EXPR
4133 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4134#endif
4135
4136 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004137 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004138 ERROR(XPATH_EXPR_ERROR);
4139 }
4140 NEXT;
4141
4142 while (CUR != ')') {
4143 xmlXPathEvalExpr(ctxt);
4144 nbargs++;
4145 if (CUR == ')') break;
4146 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004147 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004148 ERROR(XPATH_EXPR_ERROR);
4149 }
4150 NEXT;
4151 }
4152 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004153 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004154 func(ctxt, nbargs);
4155 if ((ctxt->value != top) &&
4156 (ctxt->value != NULL) &&
4157 (ctxt->value->type == XPATH_NODESET)) {
4158 xmlXPathObjectPtr cur;
4159
4160 cur = valuePop(ctxt);
4161 ctxt->context->nodelist = cur->nodesetval;
4162 ctxt->context->node = NULL;
4163 cur->nodesetval = NULL;
4164 xmlXPathFreeObject(cur);
4165 }
4166 return;
4167 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004168 /*
4169 * Simple case: no axis seach all given node types.
4170 */
4171 case NODE_TYPE_COMMENT:
4172 if ((CUR != '(') || (NXT(1) != ')')) break;
4173 SKIP(2);
4174 nodetest = NODE_TEST_TYPE;
4175 nodetype = XML_COMMENT_NODE;
4176 goto search_nodes;
4177 case NODE_TYPE_TEXT:
4178 if ((CUR != '(') || (NXT(1) != ')')) break;
4179 SKIP(2);
4180 nodetest = NODE_TEST_TYPE;
4181 nodetype = XML_TEXT_NODE;
4182 goto search_nodes;
4183 case NODE_TYPE_NODE:
4184 if ((CUR != '(') || (NXT(1) != ')')) {
4185 nodetest = NODE_TEST_NAME;
4186 break;
4187 }
4188 SKIP(2);
4189 nodetest = NODE_TEST_TYPE;
4190 nodetype = XML_ELEMENT_NODE;
4191 goto search_nodes;
4192 case NODE_TYPE_PI:
4193 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004194 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004195 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004196 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004197 xmlXPathObjectPtr cur;
4198
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004199 /*
4200 * Specific case: search a PI by name.
4201 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004202 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004203 nodetest = NODE_TEST_PI;
4204 xmlXPathEvalLiteral(ctxt);
4205 CHECK_ERROR;
4206 if (CUR != ')')
4207 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004208 NEXT;
4209 xmlXPathStringFunction(ctxt, 1);
4210 CHECK_ERROR;
4211 cur = valuePop(ctxt);
4212 name = xmlStrdup(cur->stringval);
4213 xmlXPathFreeObject(cur);
4214 } else
4215 SKIP(2);
4216 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004217 goto search_nodes;
4218
4219 /*
4220 * Handling of the compund form: got the axis.
4221 */
4222 case AXIS_ANCESTOR:
4223 case AXIS_ANCESTOR_OR_SELF:
4224 case AXIS_ATTRIBUTE:
4225 case AXIS_CHILD:
4226 case AXIS_DESCENDANT:
4227 case AXIS_DESCENDANT_OR_SELF:
4228 case AXIS_FOLLOWING:
4229 case AXIS_FOLLOWING_SIBLING:
4230 case AXIS_NAMESPACE:
4231 case AXIS_PARENT:
4232 case AXIS_PRECEDING:
4233 case AXIS_PRECEDING_SIBLING:
4234 case AXIS_SELF:
4235 if ((CUR != ':') || (NXT(1) != ':')) {
4236 nodetest = NODE_TEST_NAME;
4237 break;
4238 }
4239 SKIP(2);
4240 axis = type;
4241 break;
4242
4243 /*
4244 * Default: abbreviated syntax the axis is AXIS_CHILD
4245 */
4246 default:
4247 nodetest = NODE_TEST_NAME;
4248 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004249parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004250 if (nodetest == NODE_TEST_NONE) {
4251 if (CUR == '*') {
4252 NEXT;
4253 nodetest = NODE_TEST_ALL;
4254 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004255 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004256 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004257 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004258 if (name == NULL) {
4259 ERROR(XPATH_EXPR_ERROR);
4260 }
4261 type = xmlXPathGetNameType(ctxt, name);
4262 switch (type) {
4263 /*
4264 * Simple case: no axis seach all given node types.
4265 */
4266 case NODE_TYPE_COMMENT:
4267 if ((CUR != '(') || (NXT(1) != ')')) break;
4268 SKIP(2);
4269 nodetest = NODE_TEST_TYPE;
4270 nodetype = XML_COMMENT_NODE;
4271 goto search_nodes;
4272 case NODE_TYPE_TEXT:
4273 if ((CUR != '(') || (NXT(1) != ')')) break;
4274 SKIP(2);
4275 nodetest = NODE_TEST_TYPE;
4276 nodetype = XML_TEXT_NODE;
4277 goto search_nodes;
4278 case NODE_TYPE_NODE:
4279 if ((CUR != '(') || (NXT(1) != ')')) {
4280 nodetest = NODE_TEST_NAME;
4281 break;
4282 }
4283 SKIP(2);
4284 nodetest = NODE_TEST_TYPE;
4285 nodetype = XML_ELEMENT_NODE;
4286 goto search_nodes;
4287 case NODE_TYPE_PI:
4288 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004289 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004290 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004291 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004292 xmlXPathObjectPtr cur;
4293
Daniel Veillardb05deb71999-08-10 19:04:08 +00004294 /*
4295 * Specific case: search a PI by name.
4296 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004297 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004298 nodetest = NODE_TEST_PI;
4299 xmlXPathEvalLiteral(ctxt);
4300 CHECK_ERROR;
4301 if (CUR != ')')
4302 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004303 NEXT;
4304 xmlXPathStringFunction(ctxt, 1);
4305 CHECK_ERROR;
4306 cur = valuePop(ctxt);
4307 name = xmlStrdup(cur->stringval);
4308 xmlXPathFreeObject(cur);
4309 } else
4310 SKIP(2);
4311 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004312 goto search_nodes;
4313 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004314 nodetest = NODE_TEST_NAME;
4315 }
4316 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4317 NEXT;
4318 prefix = name;
4319 if (CUR == '*') {
4320 NEXT;
4321 nodetest = NODE_TEST_ALL;
4322 } else
4323 name = xmlXPathParseNCName(ctxt);
4324 } else if (name == NULL)
4325 ERROR(XPATH_EXPR_ERROR);
4326 }
4327
4328search_nodes:
4329
4330#ifdef DEBUG_STEP
4331 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4332#endif
4333 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4334 prefix, name);
4335 if (ctxt->context->nodelist != NULL)
4336 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4337 ctxt->context->nodelist = newset;
4338 ctxt->context->node = NULL;
4339#ifdef DEBUG_STEP
4340 fprintf(xmlXPathDebug, "Basis : ");
4341 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4342#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004343 if (name != NULL) xmlFree(name);
4344 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004345}
4346
4347/**
4348 * xmlXPathEvalStep:
4349 * @ctxt: the XPath Parser context
4350 *
4351 * [4] Step ::= Basis Predicate*
4352 * | AbbreviatedStep
4353 * [12] AbbreviatedStep ::= '.'
4354 * | '..'
4355 *
4356 * Evaluate one step in a Location Path
4357 * A location step of . is short for self::node(). This is
4358 * particularly useful in conjunction with //. For example, the
4359 * location path .//para is short for
4360 * self::node()/descendant-or-self::node()/child::para
4361 * and so will select all para descendant elements of the context
4362 * node.
4363 * Similarly, a location step of .. is short for parent::node().
4364 * For example, ../title is short for parent::node()/child::title
4365 * and so will select the title children of the parent of the context
4366 * node.
4367 */
4368void
4369xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4370 xmlNodeSetPtr newset = NULL;
4371
Daniel Veillard00fdf371999-10-08 09:40:39 +00004372 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004373 if ((CUR == '.') && (NXT(1) == '.')) {
4374 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004375 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004376 if (ctxt->context->nodelist == NULL) {
4377 STRANGE
4378 xmlXPathRoot(ctxt);
4379 }
4380 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4381 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4382 if (ctxt->context->nodelist != NULL)
4383 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4384 ctxt->context->nodelist = newset;
4385 ctxt->context->node = NULL;
4386 } else if (CUR == '.') {
4387 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004388 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004389 } else {
4390 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004391 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004392 while (CUR == '[') {
4393 xmlXPathEvalPredicate(ctxt);
4394 }
4395 }
4396#ifdef DEBUG_STEP
4397 fprintf(xmlXPathDebug, "Step : ");
4398 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4399#endif
4400}
4401
4402/**
4403 * xmlXPathEvalRelativeLocationPath:
4404 * @ctxt: the XPath Parser context
4405 *
4406 * [3] RelativeLocationPath ::= Step
4407 * | RelativeLocationPath '/' Step
4408 * | AbbreviatedRelativeLocationPath
4409 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4410 *
4411 */
4412void
4413xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4414 xmlNodeSetPtr newset = NULL;
4415
Daniel Veillard00fdf371999-10-08 09:40:39 +00004416 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004417 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004418 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004419 while (CUR == '/') {
4420 if ((CUR == '/') && (NXT(1) == '/')) {
4421 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004422 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004423 if (ctxt->context->nodelist == NULL) {
4424 STRANGE
4425 xmlXPathRoot(ctxt);
4426 }
4427 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4428 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4429 if (ctxt->context->nodelist != NULL)
4430 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4431 ctxt->context->nodelist = newset;
4432 ctxt->context->node = NULL;
4433 xmlXPathEvalStep(ctxt);
4434 } else if (CUR == '/') {
4435 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004436 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004437 xmlXPathEvalStep(ctxt);
4438 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004439 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004440 }
4441}
4442
4443/**
4444 * xmlXPathEvalLocationPath:
4445 * @ctxt: the XPath Parser context
4446 *
4447 * [1] LocationPath ::= RelativeLocationPath
4448 * | AbsoluteLocationPath
4449 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4450 * | AbbreviatedAbsoluteLocationPath
4451 * [10] AbbreviatedAbsoluteLocationPath ::=
4452 * '//' RelativeLocationPath
4453 *
4454 * // is short for /descendant-or-self::node()/. For example,
4455 * //para is short for /descendant-or-self::node()/child::para and
4456 * so will select any para element in the document (even a para element
4457 * that is a document element will be selected by //para since the
4458 * document element node is a child of the root node); div//para is
4459 * short for div/descendant-or-self::node()/child::para and so will
4460 * select all para descendants of div children.
4461 */
4462void
4463xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4464 xmlNodeSetPtr newset = NULL;
4465
Daniel Veillard00fdf371999-10-08 09:40:39 +00004466 SKIP_BLANKS;
4467 if (CUR != '/') {
4468 xmlXPathEvalRelativeLocationPath(ctxt);
4469 } else {
4470 while (CUR == '/') {
4471 if ((CUR == '/') && (NXT(1) == '/')) {
4472 SKIP(2);
4473 SKIP_BLANKS;
4474 if (ctxt->context->nodelist == NULL)
4475 xmlXPathRoot(ctxt);
4476 newset = xmlXPathNodeCollectAndTest(ctxt,
4477 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4478 XML_ELEMENT_NODE, NULL, NULL);
4479 if (ctxt->context->nodelist != NULL)
4480 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4481 ctxt->context->nodelist = newset;
4482 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004483 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004484 } else if (CUR == '/') {
4485 NEXT;
4486 SKIP_BLANKS;
4487 xmlXPathRoot(ctxt);
4488 if (CUR != 0)
4489 xmlXPathEvalRelativeLocationPath(ctxt);
4490 } else {
4491 xmlXPathEvalRelativeLocationPath(ctxt);
4492 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004493 }
4494 }
4495}
4496
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004497/**
4498 * xmlXPathEval:
4499 * @str: the XPath expression
4500 * @ctxt: the XPath context
4501 *
4502 * Evaluate the XPath Location Path in the given context.
4503 *
4504 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4505 * the caller has to free the object.
4506 */
4507xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004508xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004509 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004510 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004511 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004512
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004513 xmlXPathInit();
4514
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004515 CHECK_CONTEXT
4516
4517 if (xmlXPathDebug == NULL)
4518 xmlXPathDebug = stderr;
4519 pctxt = xmlXPathNewParserContext(str, ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004520 if (str[0] == '/')
4521 xmlXPathRoot(pctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004522 xmlXPathEvalLocationPath(pctxt);
4523
Daniel Veillardb96e6431999-08-29 21:02:19 +00004524 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004525 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004526 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004527 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004528 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004529 stack++;
4530 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004531 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004532 if (stack != 0) {
4533 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4534 stack);
4535 }
4536 if (pctxt->error == XPATH_EXPRESSION_OK)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004537 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004538 else
4539 res = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004540 xmlXPathFreeParserContext(pctxt);
4541 return(res);
4542}
4543
4544/**
4545 * xmlXPathEvalExpression:
4546 * @str: the XPath expression
4547 * @ctxt: the XPath context
4548 *
4549 * Evaluate the XPath expression in the given context.
4550 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004551 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004552 * the caller has to free the object.
4553 */
4554xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004555xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004556 xmlXPathParserContextPtr pctxt;
4557 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004558 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004559
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004560 xmlXPathInit();
4561
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004562 CHECK_CONTEXT
4563
4564 if (xmlXPathDebug == NULL)
4565 xmlXPathDebug = stderr;
4566 pctxt = xmlXPathNewParserContext(str, ctxt);
4567 xmlXPathEvalExpr(pctxt);
4568
4569 res = valuePop(pctxt);
4570 do {
4571 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004572 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004573 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004574 stack++;
4575 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004576 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004577 if (stack != 0) {
4578 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4579 stack);
4580 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004581 xmlXPathFreeParserContext(pctxt);
4582 return(res);
4583}
4584
Daniel Veillard361d8452000-04-03 19:48:13 +00004585#endif /* LIBXML_XPATH_ENABLED */