blob: b2b3c89377bda8db04831aa7e4cf7fe0c970a093 [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer.
5 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#else
19#include "config.h"
20#endif
21
22#include <stdio.h>
23#include <string.h>
24
25#ifdef HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000028#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000029#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000030#endif
31#ifdef HAVE_MATH_H
32#include <float.h>
33#endif
34#ifdef HAVE_IEEEFP_H
35#include <ieeefp.h>
36#endif
37#ifdef HAVE_NAN_H
38#include <nan.h>
39#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000040#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000041#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000042#endif
43
Daniel Veillard6454aec1999-09-02 22:04:43 +000044#include "xmlmemory.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000045#include "tree.h"
Daniel Veillardb96e6431999-08-29 21:02:19 +000046#include "valid.h"
Daniel Veillard1566d3a1999-07-15 14:24:29 +000047#include "xpath.h"
48#include "parserInternals.h"
49
Daniel Veillarddbfd6411999-12-28 16:35:14 +000050/* #define DEBUG */
51/* #define DEBUG_STEP */
52/* #define DEBUG_EXPR */
53
Daniel Veillard1566d3a1999-07-15 14:24:29 +000054/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000055 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000056 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000057 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000058double xmlXPathNAN = 0;
59double xmlXPathPINF = 1;
60double xmlXPathMINF = -1;
61
Daniel Veillardb05deb71999-08-10 19:04:08 +000062#ifndef isinf
63#ifndef HAVE_ISINF
64
65#if HAVE_FPCLASS
66
67int isinf(double d) {
68 fpclass_t type = fpclass(d);
69 switch (type) {
70 case FP_NINF:
71 return(-1);
72 case FP_PINF:
73 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000074 }
75 return(0);
76}
77
78#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
79
80#if HAVE_FP_CLASS_H
81#include <fp_class.h>
82#endif
83
84int isinf(double d) {
85#if HAVE_FP_CLASS
86 int fpclass = fp_class(d);
87#else
88 int fpclass = fp_class_d(d);
89#endif
90 if (fpclass == FP_POS_INF)
91 return(1);
92 if (fpclass == FP_NEG_INF)
93 return(-1);
94 return(0);
95}
96
97#elif defined(HAVE_CLASS)
98
99int isinf(double d) {
100 int fpclass = class(d);
101 if (fpclass == FP_PLUS_INF)
102 return(1);
103 if (fpclass == FP_MINUS_INF)
104 return(-1);
105 return(0);
106}
107#elif defined(finite) || defined(HAVE_FINITE)
108int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000109#elif defined(HUGE_VAL)
110static int isinf(double x)
111{
112 if (x == HUGE_VAL)
113 return(1);
114 if (x == -HUGE_VAL)
115 return(-1);
116 return(0);
117}
118#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000119
120#endif /* ! HAVE_ISINF */
121#endif /* ! defined(isinf) */
122
123#ifndef isnan
124#ifndef HAVE_ISNAN
125
126#ifdef HAVE_ISNAND
127#define isnan(f) isnand(f)
128#endif /* HAVE_iSNAND */
129
130#endif /* ! HAVE_iSNAN */
131#endif /* ! defined(isnan) */
132
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000133/**
134 * xmlXPathInit:
135 *
136 * Initialize the XPath environment
137 */
138void
139xmlXPathInit(void) {
140 static int initialized = 0;
141
142 if (initialized) return;
143
144 xmlXPathNAN = 0;
145 xmlXPathNAN /= 0;
146
147 xmlXPathPINF = 1;
148 xmlXPathPINF /= 0;
149
150 xmlXPathMINF = -1;
151 xmlXPathMINF /= 0;
152
153 initialized = 1;
154}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000155
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000156FILE *xmlXPathDebug = NULL;
157
158#define TODO \
159 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
160 __FILE__, __LINE__);
161
162#define STRANGE \
163 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
164 __FILE__, __LINE__);
165
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000166double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000167void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000168
169/************************************************************************
170 * *
171 * Parser stacks related functions and macros *
172 * *
173 ************************************************************************/
174
175/*
176 * Generic function for accessing stacks in the Parser Context
177 */
178
179#define PUSH_AND_POP(type, name) \
180extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
181 if (ctxt->name##Nr >= ctxt->name##Max) { \
182 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000183 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000184 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
185 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000186 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000187 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000188 } \
189 } \
190 ctxt->name##Tab[ctxt->name##Nr] = value; \
191 ctxt->name = value; \
192 return(ctxt->name##Nr++); \
193} \
194extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
195 type ret; \
196 if (ctxt->name##Nr <= 0) return(0); \
197 ctxt->name##Nr--; \
198 if (ctxt->name##Nr > 0) \
199 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
200 else \
201 ctxt->name = NULL; \
202 ret = ctxt->name##Tab[ctxt->name##Nr]; \
203 ctxt->name##Tab[ctxt->name##Nr] = 0; \
204 return(ret); \
205} \
206
207PUSH_AND_POP(xmlXPathObjectPtr, value)
208
209/*
210 * Macros for accessing the content. Those should be used only by the parser,
211 * and not exported.
212 *
213 * Dirty macros, i.e. one need to make assumption on the context to use them
214 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000215 * CUR_PTR return the current pointer to the xmlChar to be parsed.
216 * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000217 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
218 * in UNICODE mode. This should be used internally by the parser
219 * only to compare to ASCII values otherwise it would break when
220 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000221 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000222 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000223 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000224 * strings within the parser.
225 * CURRENT Returns the current char value, with the full decoding of
226 * UTF-8 if we are using this mode. It returns an int.
227 * NEXT Skip to the next character, this does the proper decoding
228 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000229 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000230 */
231
232#define CUR (*ctxt->cur)
233#define SKIP(val) ctxt->cur += (val)
234#define NXT(val) ctxt->cur[(val)]
235#define CUR_PTR ctxt->cur
236
237#define SKIP_BLANKS \
238 while (IS_BLANK(*(ctxt->cur))) NEXT
239
240#ifndef USE_UTF_8
241#define CURRENT (*ctxt->cur)
242#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
243#else
244#endif
245
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 } \
880 if (ctxt->doc->root == NULL) { \
881 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:
1499 return(ctxt->context->node->childs);
1500 case XML_ATTRIBUTE_NODE:
1501 return(NULL);
1502 case XML_DOCUMENT_NODE:
1503 case XML_DOCUMENT_TYPE_NODE:
1504 case XML_DOCUMENT_FRAG_NODE:
1505 case XML_HTML_DOCUMENT_NODE:
1506 return(((xmlDocPtr) ctxt->context->node)->root);
1507 }
1508 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001509 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001510 if ((cur->type == XML_DOCUMENT_NODE) ||
1511 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001512 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001513 return(cur->next);
1514}
1515
1516/**
1517 * mlXPathNextDescendant:
1518 * @ctxt: the XPath Parser context
1519 * @cur: the current node in the traversal
1520 *
1521 * Traversal function for the "descendant" direction
1522 * the descendant axis contains the descendants of the context node in document
1523 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001524 *
1525 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001526 */
1527xmlNodePtr
1528xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001529 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001530 if (ctxt->context->node == NULL)
1531 return(NULL);
1532 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1533 return(NULL);
1534
Daniel Veillardb05deb71999-08-10 19:04:08 +00001535 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1536 return(ctxt->context->doc->root);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001537 return(ctxt->context->node->childs);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001538 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001539
1540 if (cur->childs != NULL) return(cur->childs);
1541 if (cur->next != NULL) return(cur->next);
1542
1543 do {
1544 cur = cur->parent;
1545 if (cur == NULL) return(NULL);
1546 if (cur == ctxt->context->node) return(NULL);
1547 if (cur->next != NULL) {
1548 cur = cur->next;
1549 return(cur);
1550 }
1551 } while (cur != NULL);
1552 return(cur);
1553}
1554
1555/**
1556 * mlXPathNextDescendantOrSelf:
1557 * @ctxt: the XPath Parser context
1558 * @cur: the current node in the traversal
1559 *
1560 * Traversal function for the "descendant-or-self" direction
1561 * the descendant-or-self axis contains the context node and the descendants
1562 * of the context node in document order; thus the context node is the first
1563 * node on the axis, and the first child of the context node is the second node
1564 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001565 *
1566 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001567 */
1568xmlNodePtr
1569xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001570 if (cur == NULL) {
1571 if (ctxt->context->node == NULL)
1572 return(NULL);
1573 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1574 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001575 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001576 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001577
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001578 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001579}
1580
1581/**
1582 * xmlXPathNextParent:
1583 * @ctxt: the XPath Parser context
1584 * @cur: the current node in the traversal
1585 *
1586 * Traversal function for the "parent" direction
1587 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001588 *
1589 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001590 */
1591xmlNodePtr
1592xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1593 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001594 * the parent of an attribute or namespace node is the element
1595 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001596 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001597 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001598 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001599 if (ctxt->context->node == NULL) return(NULL);
1600 switch (ctxt->context->node->type) {
1601 case XML_ELEMENT_NODE:
1602 case XML_TEXT_NODE:
1603 case XML_CDATA_SECTION_NODE:
1604 case XML_ENTITY_REF_NODE:
1605 case XML_ENTITY_NODE:
1606 case XML_PI_NODE:
1607 case XML_COMMENT_NODE:
1608 case XML_NOTATION_NODE:
1609 if (ctxt->context->node->parent == NULL)
1610 return((xmlNodePtr) ctxt->context->doc);
1611 return(ctxt->context->node->parent);
1612 case XML_ATTRIBUTE_NODE: {
1613 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1614
1615 return(att->node);
1616 }
1617 case XML_DOCUMENT_NODE:
1618 case XML_DOCUMENT_TYPE_NODE:
1619 case XML_DOCUMENT_FRAG_NODE:
1620 case XML_HTML_DOCUMENT_NODE:
1621 return(NULL);
1622 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001623 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001624 return(NULL);
1625}
1626
1627/**
1628 * xmlXPathNextAncestor:
1629 * @ctxt: the XPath Parser context
1630 * @cur: the current node in the traversal
1631 *
1632 * Traversal function for the "ancestor" direction
1633 * the ancestor axis contains the ancestors of the context node; the ancestors
1634 * of the context node consist of the parent of context node and the parent's
1635 * parent and so on; the nodes are ordered in reverse document order; thus the
1636 * parent is the first node on the axis, and the parent's parent is the second
1637 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001638 *
1639 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001640 */
1641xmlNodePtr
1642xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1643 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001644 * the parent of an attribute or namespace node is the element
1645 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001646 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001647 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001648 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001649 if (ctxt->context->node == NULL) return(NULL);
1650 switch (ctxt->context->node->type) {
1651 case XML_ELEMENT_NODE:
1652 case XML_TEXT_NODE:
1653 case XML_CDATA_SECTION_NODE:
1654 case XML_ENTITY_REF_NODE:
1655 case XML_ENTITY_NODE:
1656 case XML_PI_NODE:
1657 case XML_COMMENT_NODE:
1658 case XML_NOTATION_NODE:
1659 if (ctxt->context->node->parent == NULL)
1660 return((xmlNodePtr) ctxt->context->doc);
1661 return(ctxt->context->node->parent);
1662 case XML_ATTRIBUTE_NODE: {
1663 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
1664
1665 return(cur->node);
1666 }
1667 case XML_DOCUMENT_NODE:
1668 case XML_DOCUMENT_TYPE_NODE:
1669 case XML_DOCUMENT_FRAG_NODE:
1670 case XML_HTML_DOCUMENT_NODE:
1671 return(NULL);
1672 }
1673 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001674 }
1675 if (cur == ctxt->context->doc->root)
1676 return((xmlNodePtr) ctxt->context->doc);
1677 if (cur == (xmlNodePtr) ctxt->context->doc)
1678 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001679 switch (cur->type) {
1680 case XML_ELEMENT_NODE:
1681 case XML_TEXT_NODE:
1682 case XML_CDATA_SECTION_NODE:
1683 case XML_ENTITY_REF_NODE:
1684 case XML_ENTITY_NODE:
1685 case XML_PI_NODE:
1686 case XML_COMMENT_NODE:
1687 case XML_NOTATION_NODE:
1688 return(cur->parent);
1689 case XML_ATTRIBUTE_NODE: {
1690 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1691
1692 return(att->node);
1693 }
1694 case XML_DOCUMENT_NODE:
1695 case XML_DOCUMENT_TYPE_NODE:
1696 case XML_DOCUMENT_FRAG_NODE:
1697 case XML_HTML_DOCUMENT_NODE:
1698 return(NULL);
1699 }
1700 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001701}
1702
1703/**
1704 * xmlXPathNextAncestorOrSelf:
1705 * @ctxt: the XPath Parser context
1706 * @cur: the current node in the traversal
1707 *
1708 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001709 * he ancestor-or-self axis contains the context node and ancestors of
1710 * the context node in reverse document order; thus the context node is
1711 * the first node on the axis, and the context node's parent the second;
1712 * parent here is defined the same as with the parent axis.
1713 *
1714 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001715 */
1716xmlNodePtr
1717xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001718 if (cur == NULL)
1719 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001720 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001721}
1722
1723/**
1724 * xmlXPathNextFollowingSibling:
1725 * @ctxt: the XPath Parser context
1726 * @cur: the current node in the traversal
1727 *
1728 * Traversal function for the "following-sibling" direction
1729 * The following-sibling axis contains the following siblings of the context
1730 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001731 *
1732 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001733 */
1734xmlNodePtr
1735xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001736 if (cur == (xmlNodePtr) ctxt->context->doc)
1737 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001738 if (cur == NULL)
1739 return(ctxt->context->node->next);
1740 return(cur->next);
1741}
1742
1743/**
1744 * xmlXPathNextPrecedingSibling:
1745 * @ctxt: the XPath Parser context
1746 * @cur: the current node in the traversal
1747 *
1748 * Traversal function for the "preceding-sibling" direction
1749 * The preceding-sibling axis contains the preceding siblings of the context
1750 * node in reverse document order; the first preceding sibling is first on the
1751 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001752 *
1753 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001754 */
1755xmlNodePtr
1756xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001757 if (cur == (xmlNodePtr) ctxt->context->doc)
1758 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001759 if (cur == NULL)
1760 return(ctxt->context->node->prev);
1761 return(cur->prev);
1762}
1763
1764/**
1765 * xmlXPathNextFollowing:
1766 * @ctxt: the XPath Parser context
1767 * @cur: the current node in the traversal
1768 *
1769 * Traversal function for the "following" direction
1770 * The following axis contains all nodes in the same document as the context
1771 * node that are after the context node in document order, excluding any
1772 * descendants and excluding attribute nodes and namespace nodes; the nodes
1773 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001774 *
1775 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001776 */
1777xmlNodePtr
1778xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001779 if (cur == (xmlNodePtr) ctxt->context->doc)
1780 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001781 if (cur == NULL)
1782 return(ctxt->context->node->next);; /* !!!!!!!!! */
1783 if (cur->childs != NULL) return(cur->childs);
1784 if (cur->next != NULL) return(cur->next);
1785
1786 do {
1787 cur = cur->parent;
1788 if (cur == NULL) return(NULL);
1789 if (cur == ctxt->context->doc->root) return(NULL);
1790 if (cur->next != NULL) {
1791 cur = cur->next;
1792 return(cur);
1793 }
1794 } while (cur != NULL);
1795 return(cur);
1796}
1797
1798/**
1799 * xmlXPathNextPreceding:
1800 * @ctxt: the XPath Parser context
1801 * @cur: the current node in the traversal
1802 *
1803 * Traversal function for the "preceding" direction
1804 * the preceding axis contains all nodes in the same document as the context
1805 * node that are before the context node in document order, excluding any
1806 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1807 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001808 *
1809 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001810 */
1811xmlNodePtr
1812xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001813 if (cur == (xmlNodePtr) ctxt->context->doc)
1814 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001815 if (cur == NULL)
1816 return(ctxt->context->node->prev); /* !!!!!!!!! */
1817 if (cur->last != NULL) return(cur->last);
1818 if (cur->prev != NULL) return(cur->prev);
1819
1820 do {
1821 cur = cur->parent;
1822 if (cur == NULL) return(NULL);
1823 if (cur == ctxt->context->doc->root) return(NULL);
1824 if (cur->prev != NULL) {
1825 cur = cur->prev;
1826 return(cur);
1827 }
1828 } while (cur != NULL);
1829 return(cur);
1830}
1831
1832/**
1833 * xmlXPathNextNamespace:
1834 * @ctxt: the XPath Parser context
1835 * @cur: the current attribute in the traversal
1836 *
1837 * Traversal function for the "namespace" direction
1838 * the namespace axis contains the namespace nodes of the context node;
1839 * the order of nodes on this axis is implementation-defined; the axis will
1840 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001841 *
1842 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001843 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001844xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001845xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001846 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1847 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001848 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001849 ctxt->context->namespaces =
1850 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1851 if (ctxt->context->namespaces == NULL) return(NULL);
1852 ctxt->context->nsNr = 0;
1853 }
1854 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001855}
1856
1857/**
1858 * xmlXPathNextAttribute:
1859 * @ctxt: the XPath Parser context
1860 * @cur: the current attribute in the traversal
1861 *
1862 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001863 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001864 *
1865 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001866 */
1867xmlAttrPtr
1868xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001869 if (cur == NULL) {
1870 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1871 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001872 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001873 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001874 return(cur->next);
1875}
1876
1877/************************************************************************
1878 * *
1879 * NodeTest Functions *
1880 * *
1881 ************************************************************************/
1882
1883#define NODE_TEST_NONE 0
1884#define NODE_TEST_TYPE 1
1885#define NODE_TEST_PI 2
1886#define NODE_TEST_ALL 3
1887#define NODE_TEST_NS 4
1888#define NODE_TEST_NAME 5
1889
1890#define NODE_TYPE_COMMENT 50
1891#define NODE_TYPE_TEXT 51
1892#define NODE_TYPE_PI 52
1893#define NODE_TYPE_NODE 53
1894
1895#define IS_FUNCTION 200
1896
1897/**
1898 * xmlXPathNodeCollectAndTest:
1899 * @ctxt: the XPath Parser context
1900 * @cur: the current node to test
1901 *
1902 * This is the function implementing a step: based on the current list
1903 * of nodes, it builds up a new list, looking at all nodes under that
1904 * axis and selecting them.
1905 *
1906 * Returns the new NodeSet resulting from the search.
1907 */
1908xmlNodeSetPtr
1909xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001910 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001911#ifdef DEBUG_STEP
1912 int n = 0, t = 0;
1913#endif
1914 int i;
1915 xmlNodeSetPtr ret;
1916 xmlXPathTraversalFunction next = NULL;
1917 xmlNodePtr cur = NULL;
1918
1919 if (ctxt->context->nodelist == NULL) {
1920 if (ctxt->context->node == NULL) {
1921 fprintf(xmlXPathDebug,
1922 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1923 __FILE__, __LINE__);
1924 return(NULL);
1925 }
1926 STRANGE
1927 return(NULL);
1928 }
1929#ifdef DEBUG_STEP
1930 fprintf(xmlXPathDebug, "new step : ");
1931#endif
1932 switch (axis) {
1933 case AXIS_ANCESTOR:
1934#ifdef DEBUG_STEP
1935 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1936#endif
1937 next = xmlXPathNextAncestor; break;
1938 case AXIS_ANCESTOR_OR_SELF:
1939#ifdef DEBUG_STEP
1940 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1941#endif
1942 next = xmlXPathNextAncestorOrSelf; break;
1943 case AXIS_ATTRIBUTE:
1944#ifdef DEBUG_STEP
1945 fprintf(xmlXPathDebug, "axis 'attributes' ");
1946#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001947 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001948 break;
1949 case AXIS_CHILD:
1950#ifdef DEBUG_STEP
1951 fprintf(xmlXPathDebug, "axis 'child' ");
1952#endif
1953 next = xmlXPathNextChild; break;
1954 case AXIS_DESCENDANT:
1955#ifdef DEBUG_STEP
1956 fprintf(xmlXPathDebug, "axis 'descendant' ");
1957#endif
1958 next = xmlXPathNextDescendant; break;
1959 case AXIS_DESCENDANT_OR_SELF:
1960#ifdef DEBUG_STEP
1961 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1962#endif
1963 next = xmlXPathNextDescendantOrSelf; break;
1964 case AXIS_FOLLOWING:
1965#ifdef DEBUG_STEP
1966 fprintf(xmlXPathDebug, "axis 'following' ");
1967#endif
1968 next = xmlXPathNextFollowing; break;
1969 case AXIS_FOLLOWING_SIBLING:
1970#ifdef DEBUG_STEP
1971 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1972#endif
1973 next = xmlXPathNextFollowingSibling; break;
1974 case AXIS_NAMESPACE:
1975#ifdef DEBUG_STEP
1976 fprintf(xmlXPathDebug, "axis 'namespace' ");
1977#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001978 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001979 break;
1980 case AXIS_PARENT:
1981#ifdef DEBUG_STEP
1982 fprintf(xmlXPathDebug, "axis 'parent' ");
1983#endif
1984 next = xmlXPathNextParent; break;
1985 case AXIS_PRECEDING:
1986#ifdef DEBUG_STEP
1987 fprintf(xmlXPathDebug, "axis 'preceding' ");
1988#endif
1989 next = xmlXPathNextPreceding; break;
1990 case AXIS_PRECEDING_SIBLING:
1991#ifdef DEBUG_STEP
1992 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1993#endif
1994 next = xmlXPathNextPrecedingSibling; break;
1995 case AXIS_SELF:
1996#ifdef DEBUG_STEP
1997 fprintf(xmlXPathDebug, "axis 'self' ");
1998#endif
1999 next = xmlXPathNextSelf; break;
2000 }
2001 if (next == NULL) return(NULL);
2002 ret = xmlXPathNodeSetCreate(NULL);
2003#ifdef DEBUG_STEP
2004 fprintf(xmlXPathDebug, " context contains %d nodes\n",
2005 ctxt->context->nodelist->nodeNr);
2006 switch (test) {
2007 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002008 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002009 break;
2010 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002011 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002012 break;
2013 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002014 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002015 break;
2016 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002017 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002018 break;
2019 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002020 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002021 prefix);
2022 break;
2023 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002024 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002025 if (prefix != NULL)
2026 fprintf(xmlXPathDebug, " with namespace %s\n",
2027 prefix);
2028 break;
2029 }
2030 fprintf(xmlXPathDebug, "Testing : ");
2031#endif
2032 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
2033 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
2034
2035 cur = NULL;
2036 do {
2037 cur = next(ctxt, cur);
2038 if (cur == NULL) break;
2039#ifdef DEBUG_STEP
2040 t++;
2041 fprintf(xmlXPathDebug, " %s", cur->name);
2042#endif
2043 switch (test) {
2044 case NODE_TEST_NONE:
2045 STRANGE
2046 return(NULL);
2047 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002048 if ((cur->type == type) ||
2049 ((type == XML_ELEMENT_NODE) &&
2050 ((cur->type == XML_DOCUMENT_NODE) ||
2051 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002052#ifdef DEBUG_STEP
2053 n++;
2054#endif
2055 xmlXPathNodeSetAdd(ret, cur);
2056 }
2057 break;
2058 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002059 if (cur->type == XML_PI_NODE) {
2060 if ((name != NULL) &&
2061 (xmlStrcmp(name, cur->name)))
2062 break;
2063#ifdef DEBUG_STEP
2064 n++;
2065#endif
2066 xmlXPathNodeSetAdd(ret, cur);
2067 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002068 break;
2069 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002070 if ((cur->type == XML_ELEMENT_NODE) ||
2071 (cur->type == XML_ATTRIBUTE_NODE)) {
2072 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002073#ifdef DEBUG_STEP
2074 n++;
2075#endif
2076 xmlXPathNodeSetAdd(ret, cur);
2077 }
2078 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002079 case NODE_TEST_NS: {
2080 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002081 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002082 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002083 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002084 switch (cur->type) {
2085 case XML_ELEMENT_NODE:
2086 if (!xmlStrcmp(name, cur->name) &&
2087 (((prefix == NULL) ||
2088 ((cur->ns != NULL) &&
2089 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002090#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002091 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002092#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002093 xmlXPathNodeSetAdd(ret, cur);
2094 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002095 break;
2096 case XML_ATTRIBUTE_NODE: {
2097 xmlAttrPtr attr = (xmlAttrPtr) cur;
2098 if (!xmlStrcmp(name, attr->name)) {
2099#ifdef DEBUG_STEP
2100 n++;
2101#endif
2102 xmlXPathNodeSetAdd(ret, cur);
2103 }
2104 break;
2105 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002106 default:
2107 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002108 }
2109 break;
2110
2111 }
2112 } while (cur != NULL);
2113 }
2114#ifdef DEBUG_STEP
2115 fprintf(xmlXPathDebug,
2116 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2117#endif
2118 return(ret);
2119}
2120
2121
2122/************************************************************************
2123 * *
2124 * Implicit tree core function library *
2125 * *
2126 ************************************************************************/
2127
2128/**
2129 * xmlXPathRoot:
2130 * @ctxt: the XPath Parser context
2131 *
2132 * Initialize the context to the root of the document
2133 */
2134void
2135xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2136 if (ctxt->context->nodelist != NULL)
2137 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002138 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2139 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002140}
2141
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002142/************************************************************************
2143 * *
2144 * The explicit core function library *
2145 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2146 * *
2147 ************************************************************************/
2148
2149
2150/**
2151 * xmlXPathLastFunction:
2152 * @ctxt: the XPath Parser context
2153 *
2154 * Implement the last() XPath function
2155 * The last function returns the number of nodes in the context node list.
2156 */
2157void
2158xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2159 CHECK_ARITY(0);
2160 if ((ctxt->context->nodelist == NULL) ||
2161 (ctxt->context->node == NULL) ||
2162 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002163 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002164 } else {
2165 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002166 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002167 }
2168}
2169
2170/**
2171 * xmlXPathPositionFunction:
2172 * @ctxt: the XPath Parser context
2173 *
2174 * Implement the position() XPath function
2175 * The position function returns the position of the context node in the
2176 * context node list. The first position is 1, and so the last positionr
2177 * will be equal to last().
2178 */
2179void
2180xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2181 int i;
2182
2183 CHECK_ARITY(0);
2184 if ((ctxt->context->nodelist == NULL) ||
2185 (ctxt->context->node == NULL) ||
2186 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002187 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002188 }
2189 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2190 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002191 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002192 return;
2193 }
2194 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002195 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002196}
2197
2198/**
2199 * xmlXPathCountFunction:
2200 * @ctxt: the XPath Parser context
2201 *
2202 * Implement the count() XPath function
2203 */
2204void
2205xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2206 xmlXPathObjectPtr cur;
2207
2208 CHECK_ARITY(1);
2209 CHECK_TYPE(XPATH_NODESET);
2210 cur = valuePop(ctxt);
2211
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002212 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002213 xmlXPathFreeObject(cur);
2214}
2215
2216/**
2217 * xmlXPathIdFunction:
2218 * @ctxt: the XPath Parser context
2219 *
2220 * Implement the id() XPath function
2221 * The id function selects elements by their unique ID
2222 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2223 * then the result is the union of the result of applying id to the
2224 * string value of each of the nodes in the argument node-set. When the
2225 * argument to id is of any other type, the argument is converted to a
2226 * string as if by a call to the string function; the string is split
2227 * into a whitespace-separated list of tokens (whitespace is any sequence
2228 * of characters matching the production S); the result is a node-set
2229 * containing the elements in the same document as the context node that
2230 * have a unique ID equal to any of the tokens in the list.
2231 */
2232void
2233xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002234 const xmlChar *tokens;
2235 const xmlChar *cur;
2236 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002237 xmlAttrPtr attr;
2238 xmlNodePtr elem = NULL;
2239 xmlXPathObjectPtr ret, obj;
2240
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002241 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002242 obj = valuePop(ctxt);
2243 if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
2244 if (obj->type == XPATH_NODESET) {
2245 TODO /* ID function in case of NodeSet */
2246 }
2247 if (obj->type != XPATH_STRING) {
2248 valuePush(ctxt, obj);
2249 xmlXPathStringFunction(ctxt, 1);
2250 obj = valuePop(ctxt);
2251 if (obj->type != XPATH_STRING) {
2252 xmlXPathFreeObject(obj);
2253 return;
2254 }
2255 }
2256 tokens = obj->stringval;
2257
2258 ret = xmlXPathNewNodeSet(NULL);
2259 valuePush(ctxt, ret);
2260 if (tokens == NULL) {
2261 xmlXPathFreeObject(obj);
2262 return;
2263 }
2264
2265 cur = tokens;
2266
2267 while (IS_BLANK(*cur)) cur++;
2268 while (*cur != 0) {
2269 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2270 (*cur == '.') || (*cur == '-') ||
2271 (*cur == '_') || (*cur == ':') ||
2272 (IS_COMBINING(*cur)) ||
2273 (IS_EXTENDER(*cur)))
2274 cur++;
2275
2276 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2277
2278 ID = xmlStrndup(tokens, cur - tokens);
2279 attr = xmlGetID(ctxt->context->doc, ID);
2280 if (attr != NULL) {
2281 elem = attr->node;
2282 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2283 }
2284 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002285 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002286
2287 while (IS_BLANK(*cur)) cur++;
2288 tokens = cur;
2289 }
2290 xmlXPathFreeObject(obj);
2291 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002292}
2293
2294/**
2295 * xmlXPathLocalPartFunction:
2296 * @ctxt: the XPath Parser context
2297 *
2298 * Implement the local-part() XPath function
2299 * The local-part function returns a string containing the local part
2300 * of the name of the node in the argument node-set that is first in
2301 * document order. If the node-set is empty or the first node has no
2302 * name, an empty string is returned. If the argument is omitted it
2303 * defaults to the context node.
2304 */
2305void
2306xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2307 xmlXPathObjectPtr cur;
2308
2309 CHECK_ARITY(1);
2310 CHECK_TYPE(XPATH_NODESET);
2311 cur = valuePop(ctxt);
2312
2313 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002314 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002315 } else {
2316 int i = 0; /* Should be first in document order !!!!! */
2317 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2318 }
2319 xmlXPathFreeObject(cur);
2320}
2321
2322/**
2323 * xmlXPathNamespaceFunction:
2324 * @ctxt: the XPath Parser context
2325 *
2326 * Implement the namespace() XPath function
2327 * The namespace function returns a string containing the namespace URI
2328 * of the expanded name of the node in the argument node-set that is
2329 * first in document order. If the node-set is empty, the first node has
2330 * no name, or the expanded name has no namespace URI, an empty string
2331 * is returned. If the argument is omitted it defaults to the context node.
2332 */
2333void
2334xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2335 xmlXPathObjectPtr cur;
2336
Daniel Veillardb96e6431999-08-29 21:02:19 +00002337 if (nargs == 0) {
2338 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2339 nargs = 1;
2340 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002341 CHECK_ARITY(1);
2342 CHECK_TYPE(XPATH_NODESET);
2343 cur = valuePop(ctxt);
2344
2345 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002346 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002347 } else {
2348 int i = 0; /* Should be first in document order !!!!! */
2349
2350 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002351 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002352 else
2353 valuePush(ctxt, xmlXPathNewString(
2354 cur->nodesetval->nodeTab[i]->ns->href));
2355 }
2356 xmlXPathFreeObject(cur);
2357}
2358
2359/**
2360 * xmlXPathNameFunction:
2361 * @ctxt: the XPath Parser context
2362 *
2363 * Implement the name() XPath function
2364 * The name function returns a string containing a QName representing
2365 * the name of the node in the argument node-set that is first in documenti
2366 * order. The QName must represent the name with respect to the namespace
2367 * declarations in effect on the node whose name is being represented.
2368 * Typically, this will be the form in which the name occurred in the XML
2369 * source. This need not be the case if there are namespace declarations
2370 * in effect on the node that associate multiple prefixes with the same
2371 * namespace. However, an implementation may include information about
2372 * the original prefix in its representation of nodes; in this case, an
2373 * implementation can ensure that the returned string is always the same
2374 * as the QName used in the XML source. If the argument it omitted it
2375 * defaults to the context node.
2376 * Libxml keep the original prefix so the "real qualified name" used is
2377 * returned.
2378 */
2379void
2380xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2381 xmlXPathObjectPtr cur;
2382
2383 CHECK_ARITY(1);
2384 CHECK_TYPE(XPATH_NODESET);
2385 cur = valuePop(ctxt);
2386
2387 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002388 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002389 } else {
2390 int i = 0; /* Should be first in document order !!!!! */
2391
2392 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2393 valuePush(ctxt, xmlXPathNewString(
2394 cur->nodesetval->nodeTab[i]->name));
2395
2396 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002397 char name[2000];
2398 sprintf(name, "%s:%s",
2399 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2400 (char *) cur->nodesetval->nodeTab[i]->name);
2401 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002402 }
2403 }
2404 xmlXPathFreeObject(cur);
2405}
2406
2407/**
2408 * xmlXPathStringFunction:
2409 * @ctxt: the XPath Parser context
2410 *
2411 * Implement the string() XPath function
2412 * he string function converts an object to a string as follows:
2413 * - A node-set is converted to a string by returning the value of
2414 * the node in the node-set that is first in document order.
2415 * If the node-set is empty, an empty string is returned.
2416 * - A number is converted to a string as follows
2417 * + NaN is converted to the string NaN
2418 * + positive zero is converted to the string 0
2419 * + negative zero is converted to the string 0
2420 * + positive infinity is converted to the string Infinity
2421 * + negative infinity is converted to the string -Infinity
2422 * + if the number is an integer, the number is represented in
2423 * decimal form as a Number with no decimal point and no leading
2424 * zeros, preceded by a minus sign (-) if the number is negative
2425 * + otherwise, the number is represented in decimal form as a
2426 * Number including a decimal point with at least one digit
2427 * before the decimal point and at least one digit after the
2428 * decimal point, preceded by a minus sign (-) if the number
2429 * is negative; there must be no leading zeros before the decimal
2430 * point apart possibly from the one required digit immediatelyi
2431 * before the decimal point; beyond the one required digit
2432 * after the decimal point there must be as many, but only as
2433 * many, more digits as are needed to uniquely distinguish the
2434 * number from all other IEEE 754 numeric values.
2435 * - The boolean false value is converted to the string false.
2436 * The boolean true value is converted to the string true.
2437 */
2438void
2439xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2440 xmlXPathObjectPtr cur;
2441
2442 CHECK_ARITY(1);
2443 cur = valuePop(ctxt);
2444 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2445 switch (cur->type) {
2446 case XPATH_NODESET:
2447 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002448 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002449 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002450 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002451 int i = 0; /* Should be first in document order !!!!! */
2452 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2453 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002454 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002455 }
2456 xmlXPathFreeObject(cur);
2457 return;
2458 case XPATH_STRING:
2459 valuePush(ctxt, cur);
2460 return;
2461 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002462 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2463 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002464 xmlXPathFreeObject(cur);
2465 return;
2466 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002467 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002468
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002469 if (isnan(cur->floatval))
2470 sprintf(buf, "NaN");
2471 else if (isinf(cur->floatval) > 0)
2472 sprintf(buf, "+Infinity");
2473 else if (isinf(cur->floatval) < 0)
2474 sprintf(buf, "-Infinity");
2475 else
2476 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002477 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002478 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002479 return;
2480 }
2481 }
2482 STRANGE
2483}
2484
2485/**
2486 * xmlXPathStringLengthFunction:
2487 * @ctxt: the XPath Parser context
2488 *
2489 * Implement the string-length() XPath function
2490 * The string-length returns the number of characters in the string
2491 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2492 * the context node converted to a string, in other words the value
2493 * of the context node.
2494 */
2495void
2496xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2497 xmlXPathObjectPtr cur;
2498
2499 if (nargs == 0) {
2500 if (ctxt->context->node == NULL) {
2501 valuePush(ctxt, xmlXPathNewFloat(0));
2502 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002503 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002504
2505 content = xmlNodeGetContent(ctxt->context->node);
2506 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002507 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002508 }
2509 return;
2510 }
2511 CHECK_ARITY(1);
2512 CHECK_TYPE(XPATH_STRING);
2513 cur = valuePop(ctxt);
2514 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2515 xmlXPathFreeObject(cur);
2516}
2517
2518/**
2519 * xmlXPathConcatFunction:
2520 * @ctxt: the XPath Parser context
2521 *
2522 * Implement the concat() XPath function
2523 * The concat function returns the concatenation of its arguments.
2524 */
2525void
2526xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2527 xmlXPathObjectPtr cur, new;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002528 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002529
2530 if (nargs < 2) {
2531 CHECK_ARITY(2);
2532 }
2533
2534 cur = valuePop(ctxt);
2535 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2536 xmlXPathFreeObject(cur);
2537 return;
2538 }
2539 nargs--;
2540
2541 while (nargs > 0) {
2542 new = valuePop(ctxt);
2543 if ((new == NULL) || (new->type != XPATH_STRING)) {
2544 xmlXPathFreeObject(new);
2545 xmlXPathFreeObject(cur);
2546 ERROR(XPATH_INVALID_TYPE);
2547 }
2548 tmp = xmlStrcat(new->stringval, cur->stringval);
2549 new->stringval = cur->stringval;
2550 cur->stringval = tmp;
2551
2552 xmlXPathFreeObject(new);
2553 nargs--;
2554 }
2555 valuePush(ctxt, cur);
2556}
2557
2558/**
2559 * xmlXPathContainsFunction:
2560 * @ctxt: the XPath Parser context
2561 *
2562 * Implement the contains() XPath function
2563 * The contains function returns true if the first argument string
2564 * contains the second argument string, and otherwise returns false.
2565 */
2566void
2567xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2568 xmlXPathObjectPtr hay, needle;
2569
2570 CHECK_ARITY(2);
2571 CHECK_TYPE(XPATH_STRING);
2572 needle = valuePop(ctxt);
2573 hay = valuePop(ctxt);
2574 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2575 xmlXPathFreeObject(hay);
2576 xmlXPathFreeObject(needle);
2577 ERROR(XPATH_INVALID_TYPE);
2578 }
2579 if (xmlStrstr(hay->stringval, needle->stringval))
2580 valuePush(ctxt, xmlXPathNewBoolean(1));
2581 else
2582 valuePush(ctxt, xmlXPathNewBoolean(0));
2583 xmlXPathFreeObject(hay);
2584 xmlXPathFreeObject(needle);
2585}
2586
2587/**
2588 * xmlXPathStartsWithFunction:
2589 * @ctxt: the XPath Parser context
2590 *
2591 * Implement the starts-with() XPath function
2592 * The starts-with function returns true if the first argument string
2593 * starts with the second argument string, and otherwise returns false.
2594 */
2595void
2596xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2597 xmlXPathObjectPtr hay, needle;
2598 int n;
2599
2600 CHECK_ARITY(2);
2601 CHECK_TYPE(XPATH_STRING);
2602 needle = valuePop(ctxt);
2603 hay = valuePop(ctxt);
2604 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2605 xmlXPathFreeObject(hay);
2606 xmlXPathFreeObject(needle);
2607 ERROR(XPATH_INVALID_TYPE);
2608 }
2609 n = xmlStrlen(needle->stringval);
2610 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2611 valuePush(ctxt, xmlXPathNewBoolean(0));
2612 else
2613 valuePush(ctxt, xmlXPathNewBoolean(1));
2614 xmlXPathFreeObject(hay);
2615 xmlXPathFreeObject(needle);
2616}
2617
2618/**
2619 * xmlXPathSubstringFunction:
2620 * @ctxt: the XPath Parser context
2621 *
2622 * Implement the substring() XPath function
2623 * The substring function returns the substring of the first argument
2624 * starting at the position specified in the second argument with
2625 * length specified in the third argument. For example,
2626 * substring("12345",2,3) returns "234". If the third argument is not
2627 * specified, it returns the substring starting at the position specified
2628 * in the second argument and continuing to the end of the string. For
2629 * example, substring("12345",2) returns "2345". More precisely, each
2630 * character in the string (see [3.6 Strings]) is considered to have a
2631 * numeric position: the position of the first character is 1, the position
2632 * of the second character is 2 and so on. The returned substring contains
2633 * those characters for which the position of the character is greater than
2634 * or equal to the second argument and, if the third argument is specified,
2635 * less than the sum of the second and third arguments; the comparisons
2636 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2637 * - substring("12345", 1.5, 2.6) returns "234"
2638 * - substring("12345", 0, 3) returns "12"
2639 * - substring("12345", 0 div 0, 3) returns ""
2640 * - substring("12345", 1, 0 div 0) returns ""
2641 * - substring("12345", -42, 1 div 0) returns "12345"
2642 * - substring("12345", -1 div 0, 1 div 0) returns ""
2643 */
2644void
2645xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2646 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002647 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002648 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002649 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002650
2651 /*
2652 * Conformance needs to be checked !!!!!
2653 */
2654 if (nargs < 2) {
2655 CHECK_ARITY(2);
2656 }
2657 if (nargs > 3) {
2658 CHECK_ARITY(3);
2659 }
2660 if (nargs == 3) {
2661 CHECK_TYPE(XPATH_NUMBER);
2662 len = valuePop(ctxt);
2663 le = len->floatval;
2664 xmlXPathFreeObject(len);
2665 } else {
2666 le = 2000000000;
2667 }
2668 CHECK_TYPE(XPATH_NUMBER);
2669 start = valuePop(ctxt);
2670 in = start->floatval;
2671 xmlXPathFreeObject(start);
2672 CHECK_TYPE(XPATH_STRING);
2673 str = valuePop(ctxt);
2674 le += in;
2675
2676 /* integer index of the first char */
2677 i = in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002678 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002679
2680 /* integer index of the last char */
2681 l = le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002682 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002683
2684 /* back to a zero based len */
2685 i--;
2686 l--;
2687
2688 /* check against the string len */
2689 if (l > 1024) {
2690 l = xmlStrlen(str->stringval);
2691 }
2692 if (i < 0) {
2693 i = 0;
2694 }
2695
2696 /* number of chars to copy */
2697 l -= i;
2698
2699 ret = xmlStrsub(str->stringval, i, l);
2700 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002701 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002702 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002703 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002704 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002705 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002706 xmlXPathFreeObject(str);
2707}
2708
2709/**
2710 * xmlXPathSubstringBeforeFunction:
2711 * @ctxt: the XPath Parser context
2712 *
2713 * Implement the substring-before() XPath function
2714 * The substring-before function returns the substring of the first
2715 * argument string that precedes the first occurrence of the second
2716 * argument string in the first argument string, or the empty string
2717 * if the first argument string does not contain the second argument
2718 * string. For example, substring-before("1999/04/01","/") returns 1999.
2719 */
2720void
2721xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2722 CHECK_ARITY(2);
2723 TODO /* substring before */
2724}
2725
2726/**
2727 * xmlXPathSubstringAfterFunction:
2728 * @ctxt: the XPath Parser context
2729 *
2730 * Implement the substring-after() XPath function
2731 * The substring-after function returns the substring of the first
2732 * argument string that follows the first occurrence of the second
2733 * argument string in the first argument string, or the empty stringi
2734 * if the first argument string does not contain the second argument
2735 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2736 * and substring-after("1999/04/01","19") returns 99/04/01.
2737 */
2738void
2739xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2740 CHECK_ARITY(2);
2741 TODO /* substring after */
2742}
2743
2744/**
2745 * xmlXPathNormalizeFunction:
2746 * @ctxt: the XPath Parser context
2747 *
2748 * Implement the normalize() XPath function
2749 * The normalize function returns the argument string with white
2750 * space normalized by stripping leading and trailing whitespace
2751 * and replacing sequences of whitespace characters by a single
2752 * space. Whitespace characters are the same allowed by the S production
2753 * in XML. If the argument is omitted, it defaults to the context
2754 * node converted to a string, in other words the value of the context node.
2755 */
2756void
2757xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2758 CHECK_ARITY(1);
2759 TODO /* normalize isn't as boring as translate, but pretty much */
2760}
2761
2762/**
2763 * xmlXPathTranslateFunction:
2764 * @ctxt: the XPath Parser context
2765 *
2766 * Implement the translate() XPath function
2767 * The translate function returns the first argument string with
2768 * occurrences of characters in the second argument string replaced
2769 * by the character at the corresponding position in the third argument
2770 * string. For example, translate("bar","abc","ABC") returns the string
2771 * BAr. If there is a character in the second argument string with no
2772 * character at a corresponding position in the third argument string
2773 * (because the second argument string is longer than the third argument
2774 * string), then occurrences of that character in the first argument
2775 * string are removed. For example, translate("--aaa--","abc-","ABC")
2776 * returns "AAA". If a character occurs more than once in second
2777 * argument string, then the first occurrence determines the replacement
2778 * character. If the third argument string is longer than the second
2779 * argument string, then excess characters are ignored.
2780 */
2781void
2782xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2783 CHECK_ARITY(3);
2784 TODO /* translate is boring, waiting for UTF-8 representation too */
2785}
2786
2787/**
2788 * xmlXPathBooleanFunction:
2789 * @ctxt: the XPath Parser context
2790 *
2791 * Implement the boolean() XPath function
2792 * he boolean function converts its argument to a boolean as follows:
2793 * - a number is true if and only if it is neither positive or
2794 * negative zero nor NaN
2795 * - a node-set is true if and only if it is non-empty
2796 * - a string is true if and only if its length is non-zero
2797 */
2798void
2799xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2800 xmlXPathObjectPtr cur;
2801 int res = 0;
2802
2803 CHECK_ARITY(1);
2804 cur = valuePop(ctxt);
2805 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2806 switch (cur->type) {
2807 case XPATH_NODESET:
2808 if ((cur->nodesetval == NULL) ||
2809 (cur->nodesetval->nodeNr == 0)) res = 0;
2810 else
2811 res = 1;
2812 break;
2813 case XPATH_STRING:
2814 if ((cur->stringval == NULL) ||
2815 (cur->stringval[0] == 0)) res = 0;
2816 else
2817 res = 1;
2818 break;
2819 case XPATH_BOOLEAN:
2820 valuePush(ctxt, cur);
2821 return;
2822 case XPATH_NUMBER:
2823 if (cur->floatval) res = 1;
2824 break;
2825 default:
2826 STRANGE
2827 }
2828 xmlXPathFreeObject(cur);
2829 valuePush(ctxt, xmlXPathNewBoolean(res));
2830}
2831
2832/**
2833 * xmlXPathNotFunction:
2834 * @ctxt: the XPath Parser context
2835 *
2836 * Implement the not() XPath function
2837 * The not function returns true if its argument is false,
2838 * and false otherwise.
2839 */
2840void
2841xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2842 CHECK_ARITY(1);
2843 CHECK_TYPE(XPATH_BOOLEAN);
2844 ctxt->value->boolval = ! ctxt->value->boolval;
2845}
2846
2847/**
2848 * xmlXPathTrueFunction:
2849 * @ctxt: the XPath Parser context
2850 *
2851 * Implement the true() XPath function
2852 */
2853void
2854xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2855 CHECK_ARITY(0);
2856 valuePush(ctxt, xmlXPathNewBoolean(1));
2857}
2858
2859/**
2860 * xmlXPathFalseFunction:
2861 * @ctxt: the XPath Parser context
2862 *
2863 * Implement the false() XPath function
2864 */
2865void
2866xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2867 CHECK_ARITY(0);
2868 valuePush(ctxt, xmlXPathNewBoolean(0));
2869}
2870
2871/**
2872 * xmlXPathLangFunction:
2873 * @ctxt: the XPath Parser context
2874 *
2875 * Implement the lang() XPath function
2876 * The lang function returns true or false depending on whether the
2877 * language of the context node as specified by xml:lang attributes
2878 * is the same as or is a sublanguage of the language specified by
2879 * the argument string. The language of the context node is determined
2880 * by the value of the xml:lang attribute on the context node, or, if
2881 * the context node has no xml:lang attribute, by the value of the
2882 * xml:lang attribute on the nearest ancestor of the context node that
2883 * has an xml:lang attribute. If there is no such attribute, then lang
2884 * returns false. If there is such an attribute, then lang returns
2885 * true if the attribute value is equal to the argument ignoring case,
2886 * or if there is some suffix starting with - such that the attribute
2887 * value is equal to the argument ignoring that suffix of the attribute
2888 * value and ignoring case.
2889 */
2890void
2891xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002892 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002893 const xmlChar *theLang;
2894 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002895 int ret = 0;
2896 int i;
2897
2898 CHECK_ARITY(1);
2899 CHECK_TYPE(XPATH_STRING);
2900 val = valuePop(ctxt);
2901 lang = val->stringval;
2902 theLang = xmlNodeGetLang(ctxt->context->node);
2903 if ((theLang != NULL) && (lang != NULL)) {
2904 for (i = 0;lang[i] != 0;i++)
2905 if (toupper(lang[i]) != toupper(theLang[i]))
2906 goto not_equal;
2907 ret = 1;
2908 }
2909not_equal:
2910 xmlXPathFreeObject(val);
2911 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002912}
2913
2914/**
2915 * xmlXPathNumberFunction:
2916 * @ctxt: the XPath Parser context
2917 *
2918 * Implement the number() XPath function
2919 */
2920void
2921xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2922 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002923 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002924
2925 CHECK_ARITY(1);
2926 cur = valuePop(ctxt);
2927 switch (cur->type) {
2928 case XPATH_NODESET:
2929 valuePush(ctxt, cur);
2930 xmlXPathStringFunction(ctxt, 1);
2931 cur = valuePop(ctxt);
2932 case XPATH_STRING:
2933 res = xmlXPathStringEvalNumber(cur->stringval);
2934 valuePush(ctxt, xmlXPathNewFloat(res));
2935 xmlXPathFreeObject(cur);
2936 return;
2937 case XPATH_BOOLEAN:
2938 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2939 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2940 xmlXPathFreeObject(cur);
2941 return;
2942 case XPATH_NUMBER:
2943 valuePush(ctxt, cur);
2944 return;
2945 }
2946 STRANGE
2947}
2948
2949/**
2950 * xmlXPathSumFunction:
2951 * @ctxt: the XPath Parser context
2952 *
2953 * Implement the sum() XPath function
2954 * The sum function returns the sum of the values of the nodes in
2955 * the argument node-set.
2956 */
2957void
2958xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2959 CHECK_ARITY(1);
2960 TODO /* BUG Sum : don't understand the definition */
2961}
2962
2963/**
2964 * xmlXPathFloorFunction:
2965 * @ctxt: the XPath Parser context
2966 *
2967 * Implement the floor() XPath function
2968 * The floor function returns the largest (closest to positive infinity)
2969 * number that is not greater than the argument and that is an integer.
2970 */
2971void
2972xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2973 CHECK_ARITY(1);
2974 CHECK_TYPE(XPATH_NUMBER);
2975 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002976 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002977}
2978
2979/**
2980 * xmlXPathCeilingFunction:
2981 * @ctxt: the XPath Parser context
2982 *
2983 * Implement the ceiling() XPath function
2984 * The ceiling function returns the smallest (closest to negative infinity)
2985 * number that is not less than the argument and that is an integer.
2986 */
2987void
2988xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002989 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002990
2991 CHECK_ARITY(1);
2992 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002993 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002994 if (f != ctxt->value->floatval)
2995 ctxt->value->floatval = f + 1;
2996}
2997
2998/**
2999 * xmlXPathRoundFunction:
3000 * @ctxt: the XPath Parser context
3001 *
3002 * Implement the round() XPath function
3003 * The round function returns the number that is closest to the
3004 * argument and that is an integer. If there are two such numbers,
3005 * then the one that is even is returned.
3006 */
3007void
3008xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003009 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003010
3011 CHECK_ARITY(1);
3012 CHECK_TYPE(XPATH_NUMBER);
3013 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003014 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003015 if (ctxt->value->floatval < f + 0.5)
3016 ctxt->value->floatval = f;
3017 else if (ctxt->value->floatval == f + 0.5)
3018 ctxt->value->floatval = f; /* !!!! Not following the spec here */
3019 else
3020 ctxt->value->floatval = f + 1;
3021}
3022
3023/************************************************************************
3024 * *
3025 * The Parser *
3026 * *
3027 ************************************************************************/
3028
3029/*
3030 * a couple of forward declarations since we use a recursive call based
3031 * implementation.
3032 */
3033void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3034void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3035void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3036void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3037
3038/**
3039 * xmlXPathParseNCName:
3040 * @ctxt: the XPath Parser context
3041 *
3042 * parse an XML namespace non qualified name.
3043 *
3044 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3045 *
3046 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3047 * CombiningChar | Extender
3048 *
3049 * Returns the namespace name or NULL
3050 */
3051
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003052xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003053xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003054 const xmlChar *q;
3055 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003056
3057 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3058 q = NEXT;
3059
3060 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3061 (CUR == '.') || (CUR == '-') ||
3062 (CUR == '_') ||
3063 (IS_COMBINING(CUR)) ||
3064 (IS_EXTENDER(CUR)))
3065 NEXT;
3066
3067 ret = xmlStrndup(q, CUR_PTR - q);
3068
3069 return(ret);
3070}
3071
3072/**
3073 * xmlXPathParseQName:
3074 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003075 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003076 *
3077 * parse an XML qualified name
3078 *
3079 * [NS 5] QName ::= (Prefix ':')? LocalPart
3080 *
3081 * [NS 6] Prefix ::= NCName
3082 *
3083 * [NS 7] LocalPart ::= NCName
3084 *
3085 * Returns the function returns the local part, and prefix is updated
3086 * to get the Prefix if any.
3087 */
3088
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003089xmlChar *
3090xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3091 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003092
3093 *prefix = NULL;
3094 ret = xmlXPathParseNCName(ctxt);
3095 if (CUR == ':') {
3096 *prefix = ret;
3097 NEXT;
3098 ret = xmlXPathParseNCName(ctxt);
3099 }
3100 return(ret);
3101}
3102
3103/**
3104 * xmlXPathStringEvalNumber:
3105 * @str: A string to scan
3106 *
3107 * [30] Number ::= Digits ('.' Digits)?
3108 * | '.' Digits
3109 * [31] Digits ::= [0-9]+
3110 *
3111 * Parse and evaluate a Number in the string
3112 *
3113 * BUG: "1.' is not valid ... James promised correction
3114 * as Digits ('.' Digits?)?
3115 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003116 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003117 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003118double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003119xmlXPathStringEvalNumber(const xmlChar *str) {
3120 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003121 double ret = 0.0;
3122 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003123 int ok = 0;
3124
3125 while (*cur == ' ') cur++;
3126 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003127 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003128 }
3129 while ((*cur >= '0') && (*cur <= '9')) {
3130 ret = ret * 10 + (*cur - '0');
3131 ok = 1;
3132 cur++;
3133 }
3134 if (*cur == '.') {
3135 cur++;
3136 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003137 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003138 }
3139 while ((*cur >= '0') && (*cur <= '9')) {
3140 mult /= 10;
3141 ret = ret + (*cur - '0') * mult;
3142 cur++;
3143 }
3144 }
3145 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003146 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003147 return(ret);
3148}
3149
3150/**
3151 * xmlXPathEvalNumber:
3152 * @ctxt: the XPath Parser context
3153 *
3154 * [30] Number ::= Digits ('.' Digits)?
3155 * | '.' Digits
3156 * [31] Digits ::= [0-9]+
3157 *
3158 * Parse and evaluate a Number, then push it on the stack
3159 *
3160 * BUG: "1.' is not valid ... James promised correction
3161 * as Digits ('.' Digits?)?
3162 */
3163void
3164xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003165 double ret = 0.0;
3166 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003167 int ok = 0;
3168
3169 CHECK_ERROR;
3170 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
3171 ERROR(XPATH_NUMBER_ERROR);
3172 }
3173 while ((CUR >= '0') && (CUR <= '9')) {
3174 ret = ret * 10 + (CUR - '0');
3175 ok = 1;
3176 NEXT;
3177 }
3178 if (CUR == '.') {
3179 NEXT;
3180 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
3181 ERROR(XPATH_NUMBER_ERROR);
3182 }
3183 while ((CUR >= '0') && (CUR <= '9')) {
3184 mult /= 10;
3185 ret = ret + (CUR - '0') * mult;
3186 NEXT;
3187 }
3188 }
3189 valuePush(ctxt, xmlXPathNewFloat(ret));
3190}
3191
3192/**
3193 * xmlXPathEvalLiteral:
3194 * @ctxt: the XPath Parser context
3195 *
3196 * Parse a Literal and push it on the stack.
3197 *
3198 * [29] Literal ::= '"' [^"]* '"'
3199 * | "'" [^']* "'"
3200 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003201 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003202 */
3203void
3204xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003205 const xmlChar *q;
3206 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003207
3208 if (CUR == '"') {
3209 NEXT;
3210 q = CUR_PTR;
3211 while ((IS_CHAR(CUR)) && (CUR != '"'))
3212 NEXT;
3213 if (!IS_CHAR(CUR)) {
3214 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3215 } else {
3216 ret = xmlStrndup(q, CUR_PTR - q);
3217 NEXT;
3218 }
3219 } else if (CUR == '\'') {
3220 NEXT;
3221 q = CUR_PTR;
3222 while ((IS_CHAR(CUR)) && (CUR != '\''))
3223 NEXT;
3224 if (!IS_CHAR(CUR)) {
3225 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
3226 } else {
3227 ret = xmlStrndup(q, CUR_PTR - q);
3228 NEXT;
3229 }
3230 } else {
3231 ERROR(XPATH_START_LITERAL_ERROR);
3232 }
3233 if (ret == NULL) return;
3234 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003235 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003236}
3237
3238/**
3239 * xmlXPathEvalVariableReference:
3240 * @ctxt: the XPath Parser context
3241 *
3242 * Parse a VariableReference, evaluate it and push it on the stack.
3243 *
3244 * The variable bindings consist of a mapping from variable names
3245 * to variable values. The value of a variable is an object, which
3246 * of any of the types that are possible for the value of an expression,
3247 * and may also be of additional types not specified here.
3248 *
3249 * Early evaluation is possible since:
3250 * The variable bindings [...] used to evaluate a subexpression are
3251 * always the same as those used to evaluate the containing expression.
3252 *
3253 * [36] VariableReference ::= '$' QName
3254 */
3255void
3256xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003257 xmlChar *name;
3258 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003259 xmlXPathObjectPtr value;
3260
3261 if (CUR != '$') {
3262 ERROR(XPATH_VARIABLE_REF_ERROR);
3263 }
3264 name = xmlXPathParseQName(ctxt, &prefix);
3265 if (name == NULL) {
3266 ERROR(XPATH_VARIABLE_REF_ERROR);
3267 }
3268 value = xmlXPathVariablelookup(ctxt, prefix, name);
3269 if (value == NULL) {
3270 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
3271 }
3272 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003273 if (prefix != NULL) xmlFree(prefix);
3274 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003275}
3276
3277
3278/**
3279 * xmlXPathFunctionLookup:
3280 * @ctxt: the XPath Parser context
3281 * @name: a name string
3282 *
3283 * Search for a function of the given name
3284 *
3285 * [35] FunctionName ::= QName - NodeType
3286 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003287 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003288 *
3289 * Returns the xmlXPathFunction if found, or NULL otherwise
3290 */
3291xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003292xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003293 switch (name[0]) {
3294 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003295 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003296 return(xmlXPathBooleanFunction);
3297 break;
3298 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003299 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003300 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003301 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003302 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003303 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003304 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003305 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003306 return(xmlXPathContainsFunction);
3307 break;
3308 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003309 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003310 return(xmlXPathIdFunction);
3311 break;
3312 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003313 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003314 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003315 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003316 return(xmlXPathFloorFunction);
3317 break;
3318 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003319 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003320 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003321 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003322 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003323 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003324 return(xmlXPathLocalPartFunction);
3325 break;
3326 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003327 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003328 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003329 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003330 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003331 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003332 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003333 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3334 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003335 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003336 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003337 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003338 return(xmlXPathNumberFunction);
3339 break;
3340 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003341 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003342 return(xmlXPathPositionFunction);
3343 break;
3344 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003345 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 return(xmlXPathRoundFunction);
3347 break;
3348 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003349 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003350 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003351 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003352 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003353 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003354 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003355 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003356 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003357 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003358 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003359 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003360 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003361 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003362 return(xmlXPathSumFunction);
3363 break;
3364 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003365 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003366 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003367 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003368 return(xmlXPathTranslateFunction);
3369 break;
3370 }
3371 return(NULL);
3372}
3373
3374/**
3375 * xmlXPathEvalLocationPathName:
3376 * @ctxt: the XPath Parser context
3377 * @name: a name string
3378 *
3379 * Various names in the beginning of a LocationPath expression
3380 * indicate whether that's an Axis, a node type,
3381 *
3382 * [6] AxisName ::= 'ancestor'
3383 * | 'ancestor-or-self'
3384 * | 'attribute'
3385 * | 'child'
3386 * | 'descendant'
3387 * | 'descendant-or-self'
3388 * | 'following'
3389 * | 'following-sibling'
3390 * | 'namespace'
3391 * | 'parent'
3392 * | 'preceding'
3393 * | 'preceding-sibling'
3394 * | 'self'
3395 * [38] NodeType ::= 'comment'
3396 * | 'text'
3397 * | 'processing-instruction'
3398 * | 'node'
3399 */
3400int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003401xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003402 switch (name[0]) {
3403 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003404 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3405 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3406 return(AXIS_ANCESTOR_OR_SELF);
3407 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003408 break;
3409 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003410 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3411 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003412 break;
3413 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003414 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3415 return(AXIS_DESCENDANT);
3416 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3417 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003418 break;
3419 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003420 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3421 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3422 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003423 break;
3424 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003425 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3426 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003427 break;
3428 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003429 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3430 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3431 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3432 return(AXIS_PRECEDING_SIBLING);
3433 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3434 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003435 break;
3436 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003437 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003438 break;
3439 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003440 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003441 break;
3442 }
3443 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3444 return(0);
3445}
3446
3447/**
3448 * xmlXPathEvalFunctionCall:
3449 * @ctxt: the XPath Parser context
3450 *
3451 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3452 * [17] Argument ::= Expr
3453 *
3454 * Parse and evaluate a function call, the evaluation of all arguments are
3455 * pushed on the stack
3456 */
3457void
3458xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003459 xmlChar *name;
3460 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003461 xmlXPathFunction func;
3462 int nbargs = 0;
3463
3464 name = xmlXPathParseQName(ctxt, &prefix);
3465 if (name == NULL) {
3466 ERROR(XPATH_EXPR_ERROR);
3467 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003468 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003469 func = xmlXPathIsFunction(ctxt, name);
3470 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003471 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003472 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
3473 }
3474#ifdef DEBUG_EXPR
3475 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3476#endif
3477
3478 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003479 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003480 ERROR(XPATH_EXPR_ERROR);
3481 }
3482 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003483 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003484
3485 while (CUR != ')') {
3486 xmlXPathEvalExpr(ctxt);
3487 nbargs++;
3488 if (CUR == ')') break;
3489 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003490 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003491 ERROR(XPATH_EXPR_ERROR);
3492 }
3493 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003494 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003495 }
3496 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003497 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003498 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003499 func(ctxt, nbargs);
3500}
3501
3502/**
3503 * xmlXPathEvalPrimaryExpr:
3504 * @ctxt: the XPath Parser context
3505 *
3506 * [15] PrimaryExpr ::= VariableReference
3507 * | '(' Expr ')'
3508 * | Literal
3509 * | Number
3510 * | FunctionCall
3511 *
3512 * Parse and evaluate a primary expression, then push the result on the stack
3513 */
3514void
3515xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003516 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003517 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3518 else if (CUR == '(') {
3519 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003520 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003521 xmlXPathEvalExpr(ctxt);
3522 if (CUR != ')') {
3523 ERROR(XPATH_EXPR_ERROR);
3524 }
3525 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003526 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003527 } else if (IS_DIGIT(CUR)) {
3528 xmlXPathEvalNumber(ctxt);
3529 } else if ((CUR == '\'') || (CUR == '"')) {
3530 xmlXPathEvalLiteral(ctxt);
3531 } else {
3532 xmlXPathEvalFunctionCall(ctxt);
3533 }
3534}
3535
3536/**
3537 * xmlXPathEvalFilterExpr:
3538 * @ctxt: the XPath Parser context
3539 *
3540 * [20] FilterExpr ::= PrimaryExpr
3541 * | FilterExpr Predicate
3542 *
3543 * Parse and evaluate a filter expression, then push the result on the stack
3544 * Square brackets are used to filter expressions in the same way that
3545 * they are used in location paths. It is an error if the expression to
3546 * be filtered does not evaluate to a node-set. The context node list
3547 * used for evaluating the expression in square brackets is the node-set
3548 * to be filtered listed in document order.
3549 */
3550
3551void
3552xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3553 /****
3554 xmlNodeSetPtr oldset = NULL;
3555 xmlXPathObjectPtr arg;
3556 ****/
3557
3558 xmlXPathEvalPrimaryExpr(ctxt);
3559 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003560 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003561
3562 if (CUR != '[') return;
3563
3564 CHECK_TYPE(XPATH_NODESET);
3565
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003566 while (CUR == '[') {
3567 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003568 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003569 }
3570
3571
3572}
3573
3574/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003575 * xmlXPathScanName:
3576 * @ctxt: the XPath Parser context
3577 *
3578 * Trickery: parse an XML name but without consuming the input flow
3579 * Needed for rollback cases.
3580 *
3581 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3582 * CombiningChar | Extender
3583 *
3584 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3585 *
3586 * [6] Names ::= Name (S Name)*
3587 *
3588 * Returns the Name parsed or NULL
3589 */
3590
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003591xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003592xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003593 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003594 int len = 0;
3595
Daniel Veillard00fdf371999-10-08 09:40:39 +00003596 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003597 if (!IS_LETTER(CUR) && (CUR != '_') &&
3598 (CUR != ':')) {
3599 return(NULL);
3600 }
3601
3602 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3603 (NXT(len) == '.') || (NXT(len) == '-') ||
3604 (NXT(len) == '_') || (NXT(len) == ':') ||
3605 (IS_COMBINING(NXT(len))) ||
3606 (IS_EXTENDER(NXT(len)))) {
3607 buf[len] = NXT(len);
3608 len++;
3609 if (len >= XML_MAX_NAMELEN) {
3610 fprintf(stderr,
3611 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3612 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3613 (NXT(len) == '.') || (NXT(len) == '-') ||
3614 (NXT(len) == '_') || (NXT(len) == ':') ||
3615 (IS_COMBINING(NXT(len))) ||
3616 (IS_EXTENDER(NXT(len))))
3617 len++;
3618 break;
3619 }
3620 }
3621 return(xmlStrndup(buf, len));
3622}
3623
3624/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003625 * xmlXPathEvalPathExpr:
3626 * @ctxt: the XPath Parser context
3627 *
3628 * [19] PathExpr ::= LocationPath
3629 * | FilterExpr
3630 * | FilterExpr '/' RelativeLocationPath
3631 * | FilterExpr '//' RelativeLocationPath
3632 *
3633 * Parse and evaluate a path expression, then push the result on the stack
3634 * The / operator and // operators combine an arbitrary expression
3635 * and a relative location path. It is an error if the expression
3636 * does not evaluate to a node-set.
3637 * The / operator does composition in the same way as when / is
3638 * used in a location path. As in location paths, // is short for
3639 * /descendant-or-self::node()/.
3640 */
3641
3642void
3643xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3644 xmlNodeSetPtr newset = NULL;
3645
Daniel Veillard00fdf371999-10-08 09:40:39 +00003646 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003647 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3648 (CUR == '\'') || (CUR == '"')) {
3649 xmlXPathEvalFilterExpr(ctxt);
3650 CHECK_ERROR;
3651 if ((CUR == '/') && (NXT(1) == '/')) {
3652 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003653 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003654 if (ctxt->context->nodelist == NULL) {
3655 STRANGE
3656 xmlXPathRoot(ctxt);
3657 }
3658 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3659 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3660 if (ctxt->context->nodelist != NULL)
3661 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3662 ctxt->context->nodelist = newset;
3663 ctxt->context->node = NULL;
3664 xmlXPathEvalRelativeLocationPath(ctxt);
3665 } else if (CUR == '/') {
3666 xmlXPathEvalRelativeLocationPath(ctxt);
3667 }
3668 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003669 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003670 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003671
3672 name = xmlXPathScanName(ctxt);
3673 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3674 xmlXPathEvalLocationPath(ctxt);
3675 else
3676 xmlXPathEvalFilterExpr(ctxt);
3677 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003678 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003679 }
3680}
3681
3682/**
3683 * xmlXPathEvalUnionExpr:
3684 * @ctxt: the XPath Parser context
3685 *
3686 * [18] UnionExpr ::= PathExpr
3687 * | UnionExpr '|' PathExpr
3688 *
3689 * Parse and evaluate an union expression, then push the result on the stack
3690 */
3691
3692void
3693xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3694 xmlXPathEvalPathExpr(ctxt);
3695 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003696 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003697 if (CUR == '|') {
3698 xmlNodeSetPtr old = ctxt->context->nodelist;
3699
Daniel Veillard00fdf371999-10-08 09:40:39 +00003700 NEXT;
3701 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003702 xmlXPathEvalPathExpr(ctxt);
3703
3704 if (ctxt->context->nodelist == NULL)
3705 ctxt->context->nodelist = old;
3706 else {
3707 ctxt->context->nodelist =
3708 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3709 xmlXPathFreeNodeSet(old);
3710 }
3711 }
3712}
3713
3714/**
3715 * xmlXPathEvalUnaryExpr:
3716 * @ctxt: the XPath Parser context
3717 *
3718 * [27] UnaryExpr ::= UnionExpr
3719 * | '-' UnaryExpr
3720 *
3721 * Parse and evaluate an unary expression, then push the result on the stack
3722 */
3723
3724void
3725xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3726 int minus = 0;
3727
Daniel Veillard00fdf371999-10-08 09:40:39 +00003728 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003729 if (CUR == '-') {
3730 minus = 1;
3731 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003732 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003733 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003734 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003735 CHECK_ERROR;
3736 if (minus) {
3737 xmlXPathValueFlipSign(ctxt);
3738 }
3739}
3740
3741/**
3742 * xmlXPathEvalMultiplicativeExpr:
3743 * @ctxt: the XPath Parser context
3744 *
3745 * [26] MultiplicativeExpr ::= UnaryExpr
3746 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3747 * | MultiplicativeExpr 'div' UnaryExpr
3748 * | MultiplicativeExpr 'mod' UnaryExpr
3749 * [34] MultiplyOperator ::= '*'
3750 *
3751 * Parse and evaluate an Additive expression, then push the result on the stack
3752 */
3753
3754void
3755xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3756 xmlXPathEvalUnaryExpr(ctxt);
3757 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003758 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003759 while ((CUR == '*') ||
3760 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3761 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3762 int op = -1;
3763
3764 if (CUR == '*') {
3765 op = 0;
3766 NEXT;
3767 } else if (CUR == 'd') {
3768 op = 1;
3769 SKIP(3);
3770 } else if (CUR == 'm') {
3771 op = 2;
3772 SKIP(3);
3773 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003774 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003775 xmlXPathEvalUnaryExpr(ctxt);
3776 CHECK_ERROR;
3777 switch (op) {
3778 case 0:
3779 xmlXPathMultValues(ctxt);
3780 break;
3781 case 1:
3782 xmlXPathDivValues(ctxt);
3783 break;
3784 case 2:
3785 xmlXPathModValues(ctxt);
3786 break;
3787 }
3788 }
3789}
3790
3791/**
3792 * xmlXPathEvalAdditiveExpr:
3793 * @ctxt: the XPath Parser context
3794 *
3795 * [25] AdditiveExpr ::= MultiplicativeExpr
3796 * | AdditiveExpr '+' MultiplicativeExpr
3797 * | AdditiveExpr '-' MultiplicativeExpr
3798 *
3799 * Parse and evaluate an Additive expression, then push the result on the stack
3800 */
3801
3802void
3803xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3804 xmlXPathEvalMultiplicativeExpr(ctxt);
3805 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003806 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003807 while ((CUR == '+') || (CUR == '-')) {
3808 int plus;
3809
3810 if (CUR == '+') plus = 1;
3811 else plus = 0;
3812 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003813 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003814 xmlXPathEvalMultiplicativeExpr(ctxt);
3815 CHECK_ERROR;
3816 if (plus) xmlXPathAddValues(ctxt);
3817 else xmlXPathSubValues(ctxt);
3818 }
3819}
3820
3821/**
3822 * xmlXPathEvalRelationalExpr:
3823 * @ctxt: the XPath Parser context
3824 *
3825 * [24] RelationalExpr ::= AdditiveExpr
3826 * | RelationalExpr '<' AdditiveExpr
3827 * | RelationalExpr '>' AdditiveExpr
3828 * | RelationalExpr '<=' AdditiveExpr
3829 * | RelationalExpr '>=' AdditiveExpr
3830 *
3831 * A <= B > C is allowed ? Answer from James, yes with
3832 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3833 * which is basically what got implemented.
3834 *
3835 * Parse and evaluate a Relational expression, then push the result
3836 * on the stack
3837 */
3838
3839void
3840xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3841 xmlXPathEvalAdditiveExpr(ctxt);
3842 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003843 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003844 while ((CUR == '<') ||
3845 (CUR == '>') ||
3846 ((CUR == '<') && (NXT(1) == '=')) ||
3847 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003848 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003849
3850 if (CUR == '<') inf = 1;
3851 else inf = 0;
3852 if (NXT(1) == '=') strict = 0;
3853 else strict = 1;
3854 NEXT;
3855 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003856 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003857 xmlXPathEvalAdditiveExpr(ctxt);
3858 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003859 ret = xmlXPathCompareValues(ctxt, inf, strict);
3860 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003861 }
3862}
3863
3864/**
3865 * xmlXPathEvalEqualityExpr:
3866 * @ctxt: the XPath Parser context
3867 *
3868 * [23] EqualityExpr ::= RelationalExpr
3869 * | EqualityExpr '=' RelationalExpr
3870 * | EqualityExpr '!=' RelationalExpr
3871 *
3872 * A != B != C is allowed ? Answer from James, yes with
3873 * (RelationalExpr = RelationalExpr) = RelationalExpr
3874 * (RelationalExpr != RelationalExpr) != RelationalExpr
3875 * which is basically what got implemented.
3876 *
3877 * Parse and evaluate an Equality expression, then push the result on the stack
3878 *
3879 */
3880void
3881xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3882 xmlXPathEvalRelationalExpr(ctxt);
3883 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003884 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003885 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003886 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003887 int eq, equal;
3888
3889 if (CUR == '=') eq = 1;
3890 else eq = 0;
3891 NEXT;
3892 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003893 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003894 xmlXPathEvalRelationalExpr(ctxt);
3895 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003896 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003897 if (eq) res = xmlXPathNewBoolean(equal);
3898 else res = xmlXPathNewBoolean(!equal);
3899 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003900 }
3901}
3902
3903/**
3904 * xmlXPathEvalAndExpr:
3905 * @ctxt: the XPath Parser context
3906 *
3907 * [22] AndExpr ::= EqualityExpr
3908 * | AndExpr 'and' EqualityExpr
3909 *
3910 * Parse and evaluate an AND expression, then push the result on the stack
3911 *
3912 */
3913void
3914xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3915 xmlXPathEvalEqualityExpr(ctxt);
3916 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003917 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003918 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3919 xmlXPathObjectPtr arg1, arg2;
3920
3921 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003922 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003923 xmlXPathEvalEqualityExpr(ctxt);
3924 CHECK_ERROR;
3925 arg2 = valuePop(ctxt);
3926 arg1 = valuePop(ctxt);
3927 arg1->boolval &= arg2->boolval;
3928 valuePush(ctxt, arg1);
3929 xmlXPathFreeObject(arg2);
3930 }
3931}
3932
3933/**
3934 * xmlXPathEvalExpr:
3935 * @ctxt: the XPath Parser context
3936 *
3937 * [14] Expr ::= OrExpr
3938 * [21] OrExpr ::= AndExpr
3939 * | OrExpr 'or' AndExpr
3940 *
3941 * Parse and evaluate an expression, then push the result on the stack
3942 *
3943 */
3944void
3945xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3946 xmlXPathEvalAndExpr(ctxt);
3947 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003948 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003949 while ((CUR == 'o') && (NXT(1) == 'r')) {
3950 xmlXPathObjectPtr arg1, arg2;
3951
3952 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003953 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003954 xmlXPathEvalAndExpr(ctxt);
3955 CHECK_ERROR;
3956 arg2 = valuePop(ctxt);
3957 arg1 = valuePop(ctxt);
3958 arg1->boolval |= arg2->boolval;
3959 valuePush(ctxt, arg1);
3960 xmlXPathFreeObject(arg2);
3961 }
3962}
3963
3964/**
3965 * xmlXPathEvaluatePredicateResult:
3966 * @ctxt: the XPath Parser context
3967 * @res: the Predicate Expression evaluation result
3968 * @index: index of the current node in the current list
3969 *
3970 * Evaluate a predicate result for the current node.
3971 * A PredicateExpr is evaluated by evaluating the Expr and converting
3972 * the result to a boolean. If the result is a number, the result will
3973 * be converted to true if the number is equal to the position of the
3974 * context node in the context node list (as returned by the position
3975 * function) and will be converted to false otherwise; if the result
3976 * is not a number, then the result will be converted as if by a call
3977 * to the boolean function.
3978 */
3979int
3980xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3981 xmlXPathObjectPtr res, int index) {
3982 if (res == NULL) return(0);
3983 switch (res->type) {
3984 case XPATH_BOOLEAN:
3985 return(res->boolval);
3986 case XPATH_NUMBER:
3987 return(res->floatval == index);
3988 case XPATH_NODESET:
3989 return(res->nodesetval->nodeNr != 0);
3990 case XPATH_STRING:
3991 return((res->stringval != NULL) &&
3992 (xmlStrlen(res->stringval) != 0));
3993 default:
3994 STRANGE
3995 }
3996 return(0);
3997}
3998
3999/**
4000 * xmlXPathEvalPredicate:
4001 * @ctxt: the XPath Parser context
4002 *
4003 * [8] Predicate ::= '[' PredicateExpr ']'
4004 * [9] PredicateExpr ::= Expr
4005 *
4006 * Parse and evaluate a predicate for all the elements of the
4007 * current node list. Then refine the list by removing all
4008 * nodes where the predicate is false.
4009 */
4010void
4011xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004012 const xmlChar *cur;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004013 xmlXPathObjectPtr res;
4014 xmlNodeSetPtr newset = NULL;
4015 int i;
4016
Daniel Veillard00fdf371999-10-08 09:40:39 +00004017 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004018 if (CUR != '[') {
4019 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4020 }
4021 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004022 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004023 if ((ctxt->context->nodelist == NULL) ||
4024 (ctxt->context->nodelist->nodeNr == 0)) {
4025 ctxt->context->node = NULL;
4026 xmlXPathEvalExpr(ctxt);
4027 CHECK_ERROR;
4028 res = valuePop(ctxt);
4029 if (res != NULL)
4030 xmlXPathFreeObject(res);
4031 } else {
4032 cur = ctxt->cur;
4033 newset = xmlXPathNodeSetCreate(NULL);
4034 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
4035 ctxt->cur = cur;
4036 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
4037 xmlXPathEvalExpr(ctxt);
4038 CHECK_ERROR;
4039 res = valuePop(ctxt);
4040 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
4041 xmlXPathNodeSetAdd(newset,
4042 ctxt->context->nodelist->nodeTab[i]);
4043 if (res != NULL)
4044 xmlXPathFreeObject(res);
4045 }
4046 if (ctxt->context->nodelist != NULL)
4047 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4048 ctxt->context->nodelist = newset;
4049 ctxt->context->node = NULL;
4050 }
4051 if (CUR != ']') {
4052 ERROR(XPATH_INVALID_PREDICATE_ERROR);
4053 }
4054 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004055 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004056#ifdef DEBUG_STEP
4057 fprintf(xmlXPathDebug, "After predicate : ");
4058 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4059#endif
4060}
4061
4062/**
4063 * xmlXPathEvalBasis:
4064 * @ctxt: the XPath Parser context
4065 *
4066 * [5] Basis ::= AxisName '::' NodeTest
4067 * | AbbreviatedBasis
4068 * [13] AbbreviatedBasis ::= NodeTest
4069 * | '@' NodeTest
4070 * [7] NodeTest ::= WildcardName
4071 * | NodeType '(' ')'
4072 * | 'processing-instruction' '(' Literal ')'
4073 * [37] WildcardName ::= '*'
4074 * | NCName ':' '*'
4075 * | QName
4076 *
4077 * Evaluate one step in a Location Path
4078 */
4079void
4080xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004081 xmlChar *name = NULL;
4082 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004083 int type = 0;
4084 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4085 int nodetest = NODE_TEST_NONE;
4086 int nodetype = 0;
4087 xmlNodeSetPtr newset = NULL;
4088
4089 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004090 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004091 axis = AXIS_ATTRIBUTE;
4092 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004093 } else if (CUR == '*') {
4094 NEXT;
4095 nodetest = NODE_TEST_ALL;
4096 } else {
4097 name = xmlXPathParseNCName(ctxt);
4098 if (name == NULL) {
4099 ERROR(XPATH_EXPR_ERROR);
4100 }
4101 type = xmlXPathGetNameType(ctxt, name);
4102 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004103 case IS_FUNCTION: {
4104 xmlXPathFunction func;
4105 int nbargs = 0;
4106 xmlXPathObjectPtr top;
4107
4108 top = ctxt->value;
4109 func = xmlXPathIsFunction(ctxt, name);
4110 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004111 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004112 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
4113 }
4114#ifdef DEBUG_EXPR
4115 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4116#endif
4117
4118 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004119 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004120 ERROR(XPATH_EXPR_ERROR);
4121 }
4122 NEXT;
4123
4124 while (CUR != ')') {
4125 xmlXPathEvalExpr(ctxt);
4126 nbargs++;
4127 if (CUR == ')') break;
4128 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004129 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004130 ERROR(XPATH_EXPR_ERROR);
4131 }
4132 NEXT;
4133 }
4134 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004135 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004136 func(ctxt, nbargs);
4137 if ((ctxt->value != top) &&
4138 (ctxt->value != NULL) &&
4139 (ctxt->value->type == XPATH_NODESET)) {
4140 xmlXPathObjectPtr cur;
4141
4142 cur = valuePop(ctxt);
4143 ctxt->context->nodelist = cur->nodesetval;
4144 ctxt->context->node = NULL;
4145 cur->nodesetval = NULL;
4146 xmlXPathFreeObject(cur);
4147 }
4148 return;
4149 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004150 /*
4151 * Simple case: no axis seach all given node types.
4152 */
4153 case NODE_TYPE_COMMENT:
4154 if ((CUR != '(') || (NXT(1) != ')')) break;
4155 SKIP(2);
4156 nodetest = NODE_TEST_TYPE;
4157 nodetype = XML_COMMENT_NODE;
4158 goto search_nodes;
4159 case NODE_TYPE_TEXT:
4160 if ((CUR != '(') || (NXT(1) != ')')) break;
4161 SKIP(2);
4162 nodetest = NODE_TEST_TYPE;
4163 nodetype = XML_TEXT_NODE;
4164 goto search_nodes;
4165 case NODE_TYPE_NODE:
4166 if ((CUR != '(') || (NXT(1) != ')')) {
4167 nodetest = NODE_TEST_NAME;
4168 break;
4169 }
4170 SKIP(2);
4171 nodetest = NODE_TEST_TYPE;
4172 nodetype = XML_ELEMENT_NODE;
4173 goto search_nodes;
4174 case NODE_TYPE_PI:
4175 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004176 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004177 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004178 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004179 xmlXPathObjectPtr cur;
4180
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004181 /*
4182 * Specific case: search a PI by name.
4183 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004184 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004185 nodetest = NODE_TEST_PI;
4186 xmlXPathEvalLiteral(ctxt);
4187 CHECK_ERROR;
4188 if (CUR != ')')
4189 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004190 NEXT;
4191 xmlXPathStringFunction(ctxt, 1);
4192 CHECK_ERROR;
4193 cur = valuePop(ctxt);
4194 name = xmlStrdup(cur->stringval);
4195 xmlXPathFreeObject(cur);
4196 } else
4197 SKIP(2);
4198 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004199 goto search_nodes;
4200
4201 /*
4202 * Handling of the compund form: got the axis.
4203 */
4204 case AXIS_ANCESTOR:
4205 case AXIS_ANCESTOR_OR_SELF:
4206 case AXIS_ATTRIBUTE:
4207 case AXIS_CHILD:
4208 case AXIS_DESCENDANT:
4209 case AXIS_DESCENDANT_OR_SELF:
4210 case AXIS_FOLLOWING:
4211 case AXIS_FOLLOWING_SIBLING:
4212 case AXIS_NAMESPACE:
4213 case AXIS_PARENT:
4214 case AXIS_PRECEDING:
4215 case AXIS_PRECEDING_SIBLING:
4216 case AXIS_SELF:
4217 if ((CUR != ':') || (NXT(1) != ':')) {
4218 nodetest = NODE_TEST_NAME;
4219 break;
4220 }
4221 SKIP(2);
4222 axis = type;
4223 break;
4224
4225 /*
4226 * Default: abbreviated syntax the axis is AXIS_CHILD
4227 */
4228 default:
4229 nodetest = NODE_TEST_NAME;
4230 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004231parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004232 if (nodetest == NODE_TEST_NONE) {
4233 if (CUR == '*') {
4234 NEXT;
4235 nodetest = NODE_TEST_ALL;
4236 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004237 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004238 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004239 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004240 if (name == NULL) {
4241 ERROR(XPATH_EXPR_ERROR);
4242 }
4243 type = xmlXPathGetNameType(ctxt, name);
4244 switch (type) {
4245 /*
4246 * Simple case: no axis seach all given node types.
4247 */
4248 case NODE_TYPE_COMMENT:
4249 if ((CUR != '(') || (NXT(1) != ')')) break;
4250 SKIP(2);
4251 nodetest = NODE_TEST_TYPE;
4252 nodetype = XML_COMMENT_NODE;
4253 goto search_nodes;
4254 case NODE_TYPE_TEXT:
4255 if ((CUR != '(') || (NXT(1) != ')')) break;
4256 SKIP(2);
4257 nodetest = NODE_TEST_TYPE;
4258 nodetype = XML_TEXT_NODE;
4259 goto search_nodes;
4260 case NODE_TYPE_NODE:
4261 if ((CUR != '(') || (NXT(1) != ')')) {
4262 nodetest = NODE_TEST_NAME;
4263 break;
4264 }
4265 SKIP(2);
4266 nodetest = NODE_TEST_TYPE;
4267 nodetype = XML_ELEMENT_NODE;
4268 goto search_nodes;
4269 case NODE_TYPE_PI:
4270 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004271 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004272 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004273 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004274 xmlXPathObjectPtr cur;
4275
Daniel Veillardb05deb71999-08-10 19:04:08 +00004276 /*
4277 * Specific case: search a PI by name.
4278 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004279 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004280 nodetest = NODE_TEST_PI;
4281 xmlXPathEvalLiteral(ctxt);
4282 CHECK_ERROR;
4283 if (CUR != ')')
4284 ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004285 NEXT;
4286 xmlXPathStringFunction(ctxt, 1);
4287 CHECK_ERROR;
4288 cur = valuePop(ctxt);
4289 name = xmlStrdup(cur->stringval);
4290 xmlXPathFreeObject(cur);
4291 } else
4292 SKIP(2);
4293 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004294 goto search_nodes;
4295 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004296 nodetest = NODE_TEST_NAME;
4297 }
4298 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4299 NEXT;
4300 prefix = name;
4301 if (CUR == '*') {
4302 NEXT;
4303 nodetest = NODE_TEST_ALL;
4304 } else
4305 name = xmlXPathParseNCName(ctxt);
4306 } else if (name == NULL)
4307 ERROR(XPATH_EXPR_ERROR);
4308 }
4309
4310search_nodes:
4311
4312#ifdef DEBUG_STEP
4313 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4314#endif
4315 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4316 prefix, name);
4317 if (ctxt->context->nodelist != NULL)
4318 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4319 ctxt->context->nodelist = newset;
4320 ctxt->context->node = NULL;
4321#ifdef DEBUG_STEP
4322 fprintf(xmlXPathDebug, "Basis : ");
4323 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4324#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004325 if (name != NULL) xmlFree(name);
4326 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004327}
4328
4329/**
4330 * xmlXPathEvalStep:
4331 * @ctxt: the XPath Parser context
4332 *
4333 * [4] Step ::= Basis Predicate*
4334 * | AbbreviatedStep
4335 * [12] AbbreviatedStep ::= '.'
4336 * | '..'
4337 *
4338 * Evaluate one step in a Location Path
4339 * A location step of . is short for self::node(). This is
4340 * particularly useful in conjunction with //. For example, the
4341 * location path .//para is short for
4342 * self::node()/descendant-or-self::node()/child::para
4343 * and so will select all para descendant elements of the context
4344 * node.
4345 * Similarly, a location step of .. is short for parent::node().
4346 * For example, ../title is short for parent::node()/child::title
4347 * and so will select the title children of the parent of the context
4348 * node.
4349 */
4350void
4351xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4352 xmlNodeSetPtr newset = NULL;
4353
Daniel Veillard00fdf371999-10-08 09:40:39 +00004354 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004355 if ((CUR == '.') && (NXT(1) == '.')) {
4356 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004357 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004358 if (ctxt->context->nodelist == NULL) {
4359 STRANGE
4360 xmlXPathRoot(ctxt);
4361 }
4362 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4363 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4364 if (ctxt->context->nodelist != NULL)
4365 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4366 ctxt->context->nodelist = newset;
4367 ctxt->context->node = NULL;
4368 } else if (CUR == '.') {
4369 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004370 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004371 } else {
4372 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004373 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004374 while (CUR == '[') {
4375 xmlXPathEvalPredicate(ctxt);
4376 }
4377 }
4378#ifdef DEBUG_STEP
4379 fprintf(xmlXPathDebug, "Step : ");
4380 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4381#endif
4382}
4383
4384/**
4385 * xmlXPathEvalRelativeLocationPath:
4386 * @ctxt: the XPath Parser context
4387 *
4388 * [3] RelativeLocationPath ::= Step
4389 * | RelativeLocationPath '/' Step
4390 * | AbbreviatedRelativeLocationPath
4391 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4392 *
4393 */
4394void
4395xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4396 xmlNodeSetPtr newset = NULL;
4397
Daniel Veillard00fdf371999-10-08 09:40:39 +00004398 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004399 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004400 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004401 while (CUR == '/') {
4402 if ((CUR == '/') && (NXT(1) == '/')) {
4403 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004404 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004405 if (ctxt->context->nodelist == NULL) {
4406 STRANGE
4407 xmlXPathRoot(ctxt);
4408 }
4409 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4410 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4411 if (ctxt->context->nodelist != NULL)
4412 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4413 ctxt->context->nodelist = newset;
4414 ctxt->context->node = NULL;
4415 xmlXPathEvalStep(ctxt);
4416 } else if (CUR == '/') {
4417 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004418 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004419 xmlXPathEvalStep(ctxt);
4420 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004421 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004422 }
4423}
4424
4425/**
4426 * xmlXPathEvalLocationPath:
4427 * @ctxt: the XPath Parser context
4428 *
4429 * [1] LocationPath ::= RelativeLocationPath
4430 * | AbsoluteLocationPath
4431 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4432 * | AbbreviatedAbsoluteLocationPath
4433 * [10] AbbreviatedAbsoluteLocationPath ::=
4434 * '//' RelativeLocationPath
4435 *
4436 * // is short for /descendant-or-self::node()/. For example,
4437 * //para is short for /descendant-or-self::node()/child::para and
4438 * so will select any para element in the document (even a para element
4439 * that is a document element will be selected by //para since the
4440 * document element node is a child of the root node); div//para is
4441 * short for div/descendant-or-self::node()/child::para and so will
4442 * select all para descendants of div children.
4443 */
4444void
4445xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4446 xmlNodeSetPtr newset = NULL;
4447
Daniel Veillard00fdf371999-10-08 09:40:39 +00004448 SKIP_BLANKS;
4449 if (CUR != '/') {
4450 xmlXPathEvalRelativeLocationPath(ctxt);
4451 } else {
4452 while (CUR == '/') {
4453 if ((CUR == '/') && (NXT(1) == '/')) {
4454 SKIP(2);
4455 SKIP_BLANKS;
4456 if (ctxt->context->nodelist == NULL)
4457 xmlXPathRoot(ctxt);
4458 newset = xmlXPathNodeCollectAndTest(ctxt,
4459 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4460 XML_ELEMENT_NODE, NULL, NULL);
4461 if (ctxt->context->nodelist != NULL)
4462 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4463 ctxt->context->nodelist = newset;
4464 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004465 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004466 } else if (CUR == '/') {
4467 NEXT;
4468 SKIP_BLANKS;
4469 xmlXPathRoot(ctxt);
4470 if (CUR != 0)
4471 xmlXPathEvalRelativeLocationPath(ctxt);
4472 } else {
4473 xmlXPathEvalRelativeLocationPath(ctxt);
4474 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004475 }
4476 }
4477}
4478
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004479/**
4480 * xmlXPathEval:
4481 * @str: the XPath expression
4482 * @ctxt: the XPath context
4483 *
4484 * Evaluate the XPath Location Path in the given context.
4485 *
4486 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4487 * the caller has to free the object.
4488 */
4489xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004490xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004491 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004492 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004493 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004494
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004495 xmlXPathInit();
4496
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004497 CHECK_CONTEXT
4498
4499 if (xmlXPathDebug == NULL)
4500 xmlXPathDebug = stderr;
4501 pctxt = xmlXPathNewParserContext(str, ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004502 if (str[0] == '/')
4503 xmlXPathRoot(pctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004504 xmlXPathEvalLocationPath(pctxt);
4505
Daniel Veillardb96e6431999-08-29 21:02:19 +00004506 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004507 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004508 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004509 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004510 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004511 stack++;
4512 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004513 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004514 if (stack != 0) {
4515 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4516 stack);
4517 }
4518 if (pctxt->error == XPATH_EXPRESSION_OK)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004519 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004520 else
4521 res = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004522 xmlXPathFreeParserContext(pctxt);
4523 return(res);
4524}
4525
4526/**
4527 * xmlXPathEvalExpression:
4528 * @str: the XPath expression
4529 * @ctxt: the XPath context
4530 *
4531 * Evaluate the XPath expression in the given context.
4532 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004533 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004534 * the caller has to free the object.
4535 */
4536xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004537xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004538 xmlXPathParserContextPtr pctxt;
4539 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004540 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004541
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004542 xmlXPathInit();
4543
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004544 CHECK_CONTEXT
4545
4546 if (xmlXPathDebug == NULL)
4547 xmlXPathDebug = stderr;
4548 pctxt = xmlXPathNewParserContext(str, ctxt);
4549 xmlXPathEvalExpr(pctxt);
4550
4551 res = valuePop(pctxt);
4552 do {
4553 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004554 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004555 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004556 stack++;
4557 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004558 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004559 if (stack != 0) {
4560 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4561 stack);
4562 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004563 xmlXPathFreeParserContext(pctxt);
4564 return(res);
4565}
4566