blob: 669e4cd3e7047203061df325acbb97bcbf1a546a [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +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 Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
19#ifdef WIN32
20#include "win32config.h"
21#else
22#include "config.h"
23#endif
24
25#include <libxml/xmlversion.h>
26#ifdef LIBXML_XPATH_ENABLED
27
28#include <stdio.h>
29#include <string.h>
30
31#ifdef HAVE_SYS_TYPES_H
32#include <sys/types.h>
33#endif
34#ifdef HAVE_MATH_H
35#include <math.h>
36#endif
37#ifdef HAVE_FLOAT_H
38#include <float.h>
39#endif
40#ifdef HAVE_IEEEFP_H
41#include <ieeefp.h>
42#endif
43#ifdef HAVE_NAN_H
44#include <nan.h>
45#endif
46#ifdef HAVE_CTYPE_H
47#include <ctype.h>
48#endif
49
50#include <libxml/xmlmemory.h>
51#include <libxml/tree.h>
52#include <libxml/valid.h>
53#include <libxml/xpath.h>
54#include <libxml/xpathInternals.h>
55#include <libxml/parserInternals.h>
56#include <libxml/hash.h>
57#ifdef LIBXML_XPTR_ENABLED
58#include <libxml/xpointer.h>
59#endif
60#ifdef LIBXML_DEBUG_ENABLED
61#include <libxml/debugXML.h>
62#endif
63#include <libxml/xmlerror.h>
64
65/* #define DEBUG */
66/* #define DEBUG_STEP */
67/* #define DEBUG_EXPR */
68
69void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
70double xmlXPathStringEvalNumber(const xmlChar *str);
71
72/*
73 * Setup stuff for floating point
74 * The lack of portability of this section of the libc is annoying !
75 */
76double xmlXPathNAN = 0;
77double xmlXPathPINF = 1;
78double xmlXPathNINF = -1;
79
80#ifndef isinf
81#ifndef HAVE_ISINF
82
83#if HAVE_FPCLASS
84
85int isinf(double d) {
86 fpclass_t type = fpclass(d);
87 switch (type) {
88 case FP_NINF:
89 return(-1);
90 case FP_PINF:
91 return(1);
92 }
93 return(0);
94}
95
96#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
97
98#if HAVE_FP_CLASS_H
99#include <fp_class.h>
100#endif
101
102int isinf(double d) {
103#if HAVE_FP_CLASS
104 int fpclass = fp_class(d);
105#else
106 int fpclass = fp_class_d(d);
107#endif
108 if (fpclass == FP_POS_INF)
109 return(1);
110 if (fpclass == FP_NEG_INF)
111 return(-1);
112 return(0);
113}
114
115#elif defined(HAVE_CLASS)
116
117int isinf(double d) {
118 int fpclass = class(d);
119 if (fpclass == FP_PLUS_INF)
120 return(1);
121 if (fpclass == FP_MINUS_INF)
122 return(-1);
123 return(0);
124}
125#elif defined(finite) || defined(HAVE_FINITE)
126int isinf(double x) { return !finite(x) && x==x; }
127#elif defined(HUGE_VAL)
128int isinf(double x)
129{
130 if (x == HUGE_VAL)
131 return(1);
132 if (x == -HUGE_VAL)
133 return(-1);
134 return(0);
135}
136#endif
137
138#endif /* ! HAVE_ISINF */
139#endif /* ! defined(isinf) */
140
141#ifndef isnan
142#ifndef HAVE_ISNAN
143
144#ifdef HAVE_ISNAND
145#define isnan(f) isnand(f)
146#endif /* HAVE_iSNAND */
147
148#endif /* ! HAVE_iSNAN */
149#endif /* ! defined(isnan) */
150
151/**
152 * xmlXPathInit:
153 *
154 * Initialize the XPath environment
155 */
156void
157xmlXPathInit(void) {
158 static int initialized = 0;
159
160 if (initialized) return;
161
162 xmlXPathNAN = 0;
163 xmlXPathNAN /= 0;
164
165 xmlXPathPINF = 1;
166 xmlXPathPINF /= 0;
167
168 xmlXPathNINF = -1;
169 xmlXPathNINF /= 0;
170
171 initialized = 1;
172}
173
174/************************************************************************
175 * *
176 * Debugging related functions *
177 * *
178 ************************************************************************/
179
180#define TODO \
181 xmlGenericError(xmlGenericErrorContext, \
182 "Unimplemented block at %s:%d\n", \
183 __FILE__, __LINE__);
184
185#define STRANGE \
186 xmlGenericError(xmlGenericErrorContext, \
187 "Internal error at %s:%d\n", \
188 __FILE__, __LINE__);
189
190#ifdef LIBXML_DEBUG_ENABLED
191void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
192 int i;
193 char shift[100];
194
195 for (i = 0;((i < depth) && (i < 25));i++)
196 shift[2 * i] = shift[2 * i + 1] = ' ';
197 shift[2 * i] = shift[2 * i + 1] = 0;
198 if (cur == NULL) {
199 fprintf(output, shift);
200 fprintf(output, "Node is NULL !\n");
201 return;
202
203 }
204
205 if ((cur->type == XML_DOCUMENT_NODE) ||
206 (cur->type == XML_HTML_DOCUMENT_NODE)) {
207 fprintf(output, shift);
208 fprintf(output, " /\n");
209 } else if (cur->type == XML_ATTRIBUTE_NODE)
210 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
211 else
212 xmlDebugDumpOneNode(output, cur, depth);
213}
214
215void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
216 int i;
217 char shift[100];
218
219 for (i = 0;((i < depth) && (i < 25));i++)
220 shift[2 * i] = shift[2 * i + 1] = ' ';
221 shift[2 * i] = shift[2 * i + 1] = 0;
222
223 if (cur == NULL) {
224 fprintf(output, shift);
225 fprintf(output, "NodeSet is NULL !\n");
226 return;
227
228 }
229
230 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
231 for (i = 0;i < cur->nodeNr;i++) {
232 fprintf(output, shift);
233 fprintf(output, "%d", i + 1);
234 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
235 }
236}
237
238#if defined(LIBXML_XPTR_ENABLED)
239void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
240void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
241 int i;
242 char shift[100];
243
244 for (i = 0;((i < depth) && (i < 25));i++)
245 shift[2 * i] = shift[2 * i + 1] = ' ';
246 shift[2 * i] = shift[2 * i + 1] = 0;
247
248 if (cur == NULL) {
249 fprintf(output, shift);
250 fprintf(output, "LocationSet is NULL !\n");
251 return;
252
253 }
254
255 for (i = 0;i < cur->locNr;i++) {
256 fprintf(output, shift);
257 fprintf(output, "%d : ", i + 1);
258 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
259 }
260}
261#endif
262
263void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
264 int i;
265 char shift[100];
266
267 for (i = 0;((i < depth) && (i < 25));i++)
268 shift[2 * i] = shift[2 * i + 1] = ' ';
269 shift[2 * i] = shift[2 * i + 1] = 0;
270
271 fprintf(output, shift);
272
273 if (cur == NULL) {
274 fprintf(output, "Object is empty (NULL)\n");
275 return;
276 }
277 switch(cur->type) {
278 case XPATH_UNDEFINED:
279 fprintf(output, "Object is uninitialized\n");
280 break;
281 case XPATH_NODESET:
282 fprintf(output, "Object is a Node Set :\n");
283 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
284 break;
285 case XPATH_XSLT_TREE:
286 fprintf(output, "Object is an XSLT value tree :\n");
287 xmlXPathDebugDumpNode(output, cur->user, depth);
288 break;
289 case XPATH_BOOLEAN:
290 fprintf(output, "Object is a Boolean : ");
291 if (cur->boolval) fprintf(output, "true\n");
292 else fprintf(output, "false\n");
293 break;
294 case XPATH_NUMBER:
295 fprintf(output, "Object is a number : %0g\n", cur->floatval);
296 break;
297 case XPATH_STRING:
298 fprintf(output, "Object is a string : ");
299 xmlDebugDumpString(output, cur->stringval);
300 fprintf(output, "\n");
301 break;
302 case XPATH_POINT:
303 fprintf(output, "Object is a point : index %d in node", cur->index);
304 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
305 fprintf(output, "\n");
306 break;
307 case XPATH_RANGE:
308 if ((cur->user2 == NULL) ||
309 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
310 fprintf(output, "Object is a collapsed range :\n");
311 fprintf(output, shift);
312 if (cur->index >= 0)
313 fprintf(output, "index %d in ", cur->index);
314 fprintf(output, "node\n");
315 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
316 depth + 1);
317 } else {
318 fprintf(output, "Object is a range :\n");
319 fprintf(output, shift);
320 fprintf(output, "From ");
321 if (cur->index >= 0)
322 fprintf(output, "index %d in ", cur->index);
323 fprintf(output, "node\n");
324 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
325 depth + 1);
326 fprintf(output, shift);
327 fprintf(output, "To ");
328 if (cur->index2 >= 0)
329 fprintf(output, "index %d in ", cur->index2);
330 fprintf(output, "node\n");
331 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
332 depth + 1);
333 fprintf(output, "\n");
334 }
335 break;
336 case XPATH_LOCATIONSET:
337#if defined(LIBXML_XPTR_ENABLED)
338 fprintf(output, "Object is a Location Set:\n");
339 xmlXPathDebugDumpLocationSet(output,
340 (xmlLocationSetPtr) cur->user, depth);
341#endif
342 break;
343 case XPATH_USERS:
344 fprintf(output, "Object is user defined\n");
345 break;
346 }
347}
348#endif
349
350/************************************************************************
351 * *
352 * Parser stacks related functions and macros *
353 * *
354 ************************************************************************/
355
356/*
357 * Generic function for accessing stacks in the Parser Context
358 */
359
360#define PUSH_AND_POP(type, name) \
361extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
362 if (ctxt->name##Nr >= ctxt->name##Max) { \
363 ctxt->name##Max *= 2; \
364 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
365 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
366 if (ctxt->name##Tab == NULL) { \
367 xmlGenericError(xmlGenericErrorContext, \
368 "realloc failed !\n"); \
369 return(0); \
370 } \
371 } \
372 ctxt->name##Tab[ctxt->name##Nr] = value; \
373 ctxt->name = value; \
374 return(ctxt->name##Nr++); \
375} \
376extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
377 type ret; \
378 if (ctxt->name##Nr <= 0) return(0); \
379 ctxt->name##Nr--; \
380 if (ctxt->name##Nr > 0) \
381 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
382 else \
383 ctxt->name = NULL; \
384 ret = ctxt->name##Tab[ctxt->name##Nr]; \
385 ctxt->name##Tab[ctxt->name##Nr] = 0; \
386 return(ret); \
387} \
388
389PUSH_AND_POP(xmlXPathObjectPtr, value)
390
391/*
392 * Macros for accessing the content. Those should be used only by the parser,
393 * and not exported.
394 *
395 * Dirty macros, i.e. one need to make assumption on the context to use them
396 *
397 * CUR_PTR return the current pointer to the xmlChar to be parsed.
398 * CUR returns the current xmlChar value, i.e. a 8 bit value
399 * in ISO-Latin or UTF-8.
400 * This should be used internally by the parser
401 * only to compare to ASCII values otherwise it would break when
402 * running with UTF-8 encoding.
403 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
404 * to compare on ASCII based substring.
405 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
406 * strings within the parser.
407 * CURRENT Returns the current char value, with the full decoding of
408 * UTF-8 if we are using this mode. It returns an int.
409 * NEXT Skip to the next character, this does the proper decoding
410 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
411 * It returns the pointer to the current xmlChar.
412 */
413
414#define CUR (*ctxt->cur)
415#define SKIP(val) ctxt->cur += (val)
416#define NXT(val) ctxt->cur[(val)]
417#define CUR_PTR ctxt->cur
418
419#define SKIP_BLANKS \
420 while (IS_BLANK(*(ctxt->cur))) NEXT
421
422#define CURRENT (*ctxt->cur)
423#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
424
425/************************************************************************
426 * *
427 * Error handling routines *
428 * *
429 ************************************************************************/
430
431
432const char *xmlXPathErrorMessages[] = {
433 "Ok",
434 "Number encoding",
435 "Unfinished litteral",
436 "Start of litteral",
437 "Expected $ for variable reference",
438 "Undefined variable",
439 "Invalid predicate",
440 "Invalid expression",
441 "Missing closing curly brace",
442 "Unregistered function",
443 "Invalid operand",
444 "Invalid type",
445 "Invalid number of arguments",
446 "Invalid context size",
447 "Invalid context position",
448 "Memory allocation error",
449 "Syntax error",
450 "Resource error",
451 "Sub resource error",
452 "Undefined namespace prefix"
453};
454
455/**
456 * xmlXPathError:
457 * @ctxt: the XPath Parser context
458 * @file: the file name
459 * @line: the line number
460 * @no: the error number
461 *
462 * Create a new xmlNodeSetPtr of type double and of value @val
463 *
464 * Returns the newly created object.
465 */
466void
467xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
468 int line, int no) {
469 int n;
470 const xmlChar *cur;
471 const xmlChar *base;
472
473 xmlGenericError(xmlGenericErrorContext,
474 "Error %s:%d: %s\n", file, line,
475 xmlXPathErrorMessages[no]);
476
477 cur = ctxt->cur;
478 base = ctxt->base;
479 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
480 cur--;
481 }
482 n = 0;
483 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
484 cur--;
485 if ((*cur == '\n') || (*cur == '\r')) cur++;
486 base = cur;
487 n = 0;
488 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
489 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
490 n++;
491 }
492 xmlGenericError(xmlGenericErrorContext, "\n");
493 cur = ctxt->cur;
494 while ((*cur == '\n') || (*cur == '\r'))
495 cur--;
496 n = 0;
497 while ((cur != base) && (n++ < 80)) {
498 xmlGenericError(xmlGenericErrorContext, " ");
499 base++;
500 }
501 xmlGenericError(xmlGenericErrorContext,"^\n");
502}
503
504
505/************************************************************************
506 * *
507 * Routines to handle NodeSets *
508 * *
509 ************************************************************************/
510
511/**
512 * xmlXPathCmpNodes:
513 * @node1: the first node
514 * @node2: the second node
515 *
516 * Compare two nodes w.r.t document order
517 *
518 * Returns -2 in case of error 1 if first point < second point, 0 if
519 * that's the same node, -1 otherwise
520 */
521int
522xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
523 int depth1, depth2;
524 xmlNodePtr cur, root;
525
526 if ((node1 == NULL) || (node2 == NULL))
527 return(-2);
528 /*
529 * a couple of optimizations which will avoid computations in most cases
530 */
531 if (node1 == node2)
532 return(0);
533 if (node1 == node2->prev)
534 return(1);
535 if (node1 == node2->next)
536 return(-1);
537
538 /*
539 * compute depth to root
540 */
541 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
542 if (cur == node1)
543 return(1);
544 depth2++;
545 }
546 root = cur;
547 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
548 if (cur == node2)
549 return(-1);
550 depth1++;
551 }
552 /*
553 * Distinct document (or distinct entities :-( ) case.
554 */
555 if (root != cur) {
556 return(-2);
557 }
558 /*
559 * get the nearest common ancestor.
560 */
561 while (depth1 > depth2) {
562 depth1--;
563 node1 = node1->parent;
564 }
565 while (depth2 > depth1) {
566 depth2--;
567 node2 = node2->parent;
568 }
569 while (node1->parent != node2->parent) {
570 node1 = node1->parent;
571 node2 = node2->parent;
572 /* should not happen but just in case ... */
573 if ((node1 == NULL) || (node2 == NULL))
574 return(-2);
575 }
576 /*
577 * Find who's first.
578 */
579 if (node1 == node2->next)
580 return(-1);
581 for (cur = node1->next;cur != NULL;cur = cur->next)
582 if (cur == node2)
583 return(1);
584 return(-1); /* assume there is no sibling list corruption */
585}
586
587/**
588 * xmlXPathNodeSetSort:
589 * @set: the node set
590 *
591 * Sort the node set in document order
592 */
593void
594xmlXPathNodeSetSort(xmlNodeSetPtr set) {
595 int i, j, incr, len, rc;
596 xmlNodePtr tmp;
597
598 if (set == NULL)
599 return;
600
601 /* Use Shell's sort to sort the node-set */
602 len = set->nodeNr;
603 for (incr = len / 2; incr > 0; incr /= 2) {
604 for (i = incr; i < len; i++) {
605 j = i - incr;
606 while (j >= 0) {
607 rc = xmlXPathCmpNodes(set->nodeTab[j], set->nodeTab[j + incr]);
608 if (rc != 1 && rc != -2) {
609 tmp = set->nodeTab[j];
610 set->nodeTab[j] = set->nodeTab[j + incr];
611 set->nodeTab[j + incr] = tmp;
612 j -= incr;
613 } else
614 break;
615 }
616 }
617 }
618}
619
620#define XML_NODESET_DEFAULT 10
621/**
622 * xmlXPathNodeSetCreate:
623 * @val: an initial xmlNodePtr, or NULL
624 *
625 * Create a new xmlNodeSetPtr of type double and of value @val
626 *
627 * Returns the newly created object.
628 */
629xmlNodeSetPtr
630xmlXPathNodeSetCreate(xmlNodePtr val) {
631 xmlNodeSetPtr ret;
632
633 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
634 if (ret == NULL) {
635 xmlGenericError(xmlGenericErrorContext,
636 "xmlXPathNewNodeSet: out of memory\n");
637 return(NULL);
638 }
639 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
640 if (val != NULL) {
641 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
642 sizeof(xmlNodePtr));
643 if (ret->nodeTab == NULL) {
644 xmlGenericError(xmlGenericErrorContext,
645 "xmlXPathNewNodeSet: out of memory\n");
646 return(NULL);
647 }
648 memset(ret->nodeTab, 0 ,
649 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
650 ret->nodeMax = XML_NODESET_DEFAULT;
651 ret->nodeTab[ret->nodeNr++] = val;
652 }
653 return(ret);
654}
655
656/**
657 * xmlXPathNodeSetAdd:
658 * @cur: the initial node set
659 * @val: a new xmlNodePtr
660 *
661 * add a new xmlNodePtr ot an existing NodeSet
662 */
663void
664xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
665 int i;
666
667 if (val == NULL) return;
668
669 /*
670 * check against doublons
671 */
672 for (i = 0;i < cur->nodeNr;i++)
673 if (cur->nodeTab[i] == val) return;
674
675 /*
676 * grow the nodeTab if needed
677 */
678 if (cur->nodeMax == 0) {
679 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
680 sizeof(xmlNodePtr));
681 if (cur->nodeTab == NULL) {
682 xmlGenericError(xmlGenericErrorContext,
683 "xmlXPathNodeSetAdd: out of memory\n");
684 return;
685 }
686 memset(cur->nodeTab, 0 ,
687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
688 cur->nodeMax = XML_NODESET_DEFAULT;
689 } else if (cur->nodeNr == cur->nodeMax) {
690 xmlNodePtr *temp;
691
692 cur->nodeMax *= 2;
693 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
694 sizeof(xmlNodePtr));
695 if (temp == NULL) {
696 xmlGenericError(xmlGenericErrorContext,
697 "xmlXPathNodeSetAdd: out of memory\n");
698 return;
699 }
700 cur->nodeTab = temp;
701 }
702 cur->nodeTab[cur->nodeNr++] = val;
703}
704
705/**
706 * xmlXPathNodeSetAddUnique:
707 * @cur: the initial node set
708 * @val: a new xmlNodePtr
709 *
710 * add a new xmlNodePtr ot an existing NodeSet, optimized version
711 * when we are sure the node is not already in the set.
712 */
713void
714xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
715 if (val == NULL) return;
716
717 /*
718 * grow the nodeTab if needed
719 */
720 if (cur->nodeMax == 0) {
721 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
722 sizeof(xmlNodePtr));
723 if (cur->nodeTab == NULL) {
724 xmlGenericError(xmlGenericErrorContext,
725 "xmlXPathNodeSetAddUnique: out of memory\n");
726 return;
727 }
728 memset(cur->nodeTab, 0 ,
729 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
730 cur->nodeMax = XML_NODESET_DEFAULT;
731 } else if (cur->nodeNr == cur->nodeMax) {
732 xmlNodePtr *temp;
733
734 cur->nodeMax *= 2;
735 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
736 sizeof(xmlNodePtr));
737 if (temp == NULL) {
738 xmlGenericError(xmlGenericErrorContext,
739 "xmlXPathNodeSetAddUnique: out of memory\n");
740 return;
741 }
742 cur->nodeTab = temp;
743 }
744 cur->nodeTab[cur->nodeNr++] = val;
745}
746
747/**
748 * xmlXPathNodeSetMerge:
749 * @val1: the first NodeSet or NULL
750 * @val2: the second NodeSet
751 *
752 * Merges two nodesets, all nodes from @val2 are added to @val1
753 * if @val1 is NULL, a new set is created and copied from @val2
754 *
755 * Returns val1 once extended or NULL in case of error.
756 */
757xmlNodeSetPtr
758xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
759 int i, j, initNr;
760
761 if (val2 == NULL) return(val1);
762 if (val1 == NULL) {
763 val1 = xmlXPathNodeSetCreate(NULL);
764 }
765
766 initNr = val1->nodeNr;
767
768 for (i = 0;i < val2->nodeNr;i++) {
769 /*
770 * check against doublons
771 */
772 for (j = 0; j < initNr; j++)
773 if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
774
775 /*
776 * grow the nodeTab if needed
777 */
778 if (val1->nodeMax == 0) {
779 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
780 sizeof(xmlNodePtr));
781 if (val1->nodeTab == NULL) {
782 xmlGenericError(xmlGenericErrorContext,
783 "xmlXPathNodeSetMerge: out of memory\n");
784 return(NULL);
785 }
786 memset(val1->nodeTab, 0 ,
787 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
788 val1->nodeMax = XML_NODESET_DEFAULT;
789 } else if (val1->nodeNr == val1->nodeMax) {
790 xmlNodePtr *temp;
791
792 val1->nodeMax *= 2;
793 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
794 sizeof(xmlNodePtr));
795 if (temp == NULL) {
796 xmlGenericError(xmlGenericErrorContext,
797 "xmlXPathNodeSetMerge: out of memory\n");
798 return(NULL);
799 }
800 val1->nodeTab = temp;
801 }
802 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
803 }
804
805 return(val1);
806}
807
808/**
809 * xmlXPathNodeSetDel:
810 * @cur: the initial node set
811 * @val: an xmlNodePtr
812 *
813 * Removes an xmlNodePtr from an existing NodeSet
814 */
815void
816xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
817 int i;
818
819 if (cur == NULL) return;
820 if (val == NULL) return;
821
822 /*
823 * check against doublons
824 */
825 for (i = 0;i < cur->nodeNr;i++)
826 if (cur->nodeTab[i] == val) break;
827
828 if (i >= cur->nodeNr) {
829#ifdef DEBUG
830 xmlGenericError(xmlGenericErrorContext,
831 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
832 val->name);
833#endif
834 return;
835 }
836 cur->nodeNr--;
837 for (;i < cur->nodeNr;i++)
838 cur->nodeTab[i] = cur->nodeTab[i + 1];
839 cur->nodeTab[cur->nodeNr] = NULL;
840}
841
842/**
843 * xmlXPathNodeSetRemove:
844 * @cur: the initial node set
845 * @val: the index to remove
846 *
847 * Removes an entry from an existing NodeSet list.
848 */
849void
850xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
851 if (cur == NULL) return;
852 if (val >= cur->nodeNr) return;
853 cur->nodeNr--;
854 for (;val < cur->nodeNr;val++)
855 cur->nodeTab[val] = cur->nodeTab[val + 1];
856 cur->nodeTab[cur->nodeNr] = NULL;
857}
858
859/**
860 * xmlXPathFreeNodeSet:
861 * @obj: the xmlNodeSetPtr to free
862 *
863 * Free the NodeSet compound (not the actual nodes !).
864 */
865void
866xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
867 if (obj == NULL) return;
868 if (obj->nodeTab != NULL) {
869#ifdef DEBUG
870 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
871#endif
872 xmlFree(obj->nodeTab);
873 }
874#ifdef DEBUG
875 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
876#endif
877 xmlFree(obj);
878}
879
880/**
881 * xmlXPathFreeValueTree:
882 * @obj: the xmlNodeSetPtr to free
883 *
884 * Free the NodeSet compound and the actual tree, this is different
885 * from xmlXPathFreeNodeSet()
886 */
887void
888xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
889 int i;
890
891 if (obj == NULL) return;
892 for (i = 0;i < obj->nodeNr;i++)
893 if (obj->nodeTab[i] != NULL)
894 xmlFreeNode(obj->nodeTab[i]);
895
896 if (obj->nodeTab != NULL) {
897#ifdef DEBUG
898 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
899#endif
900 xmlFree(obj->nodeTab);
901 }
902#ifdef DEBUG
903 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
904#endif
905 xmlFree(obj);
906}
907
908#if defined(DEBUG) || defined(DEBUG_STEP)
909/**
910 * xmlGenericErrorContextNodeSet:
911 * @output: a FILE * for the output
912 * @obj: the xmlNodeSetPtr to free
913 *
914 * Quick display of a NodeSet
915 */
916void
917xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
918 int i;
919
920 if (output == NULL) output = xmlGenericErrorContext;
921 if (obj == NULL) {
922 fprintf(output, "NodeSet == NULL !\n");
923 return;
924 }
925 if (obj->nodeNr == 0) {
926 fprintf(output, "NodeSet is empty\n");
927 return;
928 }
929 if (obj->nodeTab == NULL) {
930 fprintf(output, " nodeTab == NULL !\n");
931 return;
932 }
933 for (i = 0; i < obj->nodeNr; i++) {
934 if (obj->nodeTab[i] == NULL) {
935 fprintf(output, " NULL !\n");
936 return;
937 }
938 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
939 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
940 fprintf(output, " /");
941 else if (obj->nodeTab[i]->name == NULL)
942 fprintf(output, " noname!");
943 else fprintf(output, " %s", obj->nodeTab[i]->name);
944 }
945 fprintf(output, "\n");
946}
947#endif
948
949/**
950 * xmlXPathNewNodeSet:
951 * @val: the NodePtr value
952 *
953 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
954 * it with the single Node @val
955 *
956 * Returns the newly created object.
957 */
958xmlXPathObjectPtr
959xmlXPathNewNodeSet(xmlNodePtr val) {
960 xmlXPathObjectPtr ret;
961
962 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
963 if (ret == NULL) {
964 xmlGenericError(xmlGenericErrorContext,
965 "xmlXPathNewNodeSet: out of memory\n");
966 return(NULL);
967 }
968 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
969 ret->type = XPATH_NODESET;
970 ret->nodesetval = xmlXPathNodeSetCreate(val);
971 return(ret);
972}
973
974/**
975 * xmlXPathNewValueTree:
976 * @val: the NodePtr value
977 *
978 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
979 * it with the tree root @val
980 *
981 * Returns the newly created object.
982 */
983xmlXPathObjectPtr
984xmlXPathNewValueTree(xmlNodePtr val) {
985 xmlXPathObjectPtr ret;
986
987 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
988 if (ret == NULL) {
989 xmlGenericError(xmlGenericErrorContext,
990 "xmlXPathNewNodeSet: out of memory\n");
991 return(NULL);
992 }
993 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
994 ret->type = XPATH_XSLT_TREE;
995 ret->nodesetval = xmlXPathNodeSetCreate(val);
996 return(ret);
997}
998
999/**
1000 * xmlXPathNewNodeSetList:
1001 * @val: an existing NodeSet
1002 *
1003 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1004 * it with the Nodeset @val
1005 *
1006 * Returns the newly created object.
1007 */
1008xmlXPathObjectPtr
1009xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1010 xmlXPathObjectPtr ret;
1011 int i;
1012
1013 if (val == NULL)
1014 ret = NULL;
1015 else if (val->nodeTab == NULL)
1016 ret = xmlXPathNewNodeSet(NULL);
1017 else
1018 {
1019 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1020 for (i = 1; i < val->nodeNr; ++i)
1021 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1022 }
1023
1024 return(ret);
1025}
1026
1027/**
1028 * xmlXPathWrapNodeSet:
1029 * @val: the NodePtr value
1030 *
1031 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1032 *
1033 * Returns the newly created object.
1034 */
1035xmlXPathObjectPtr
1036xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1037 xmlXPathObjectPtr ret;
1038
1039 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1040 if (ret == NULL) {
1041 xmlGenericError(xmlGenericErrorContext,
1042 "xmlXPathWrapNodeSet: out of memory\n");
1043 return(NULL);
1044 }
1045 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1046 ret->type = XPATH_NODESET;
1047 ret->nodesetval = val;
1048 return(ret);
1049}
1050
1051/**
1052 * xmlXPathFreeNodeSetList:
1053 * @obj: an existing NodeSetList object
1054 *
1055 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1056 * the list contrary to xmlXPathFreeObject().
1057 */
1058void
1059xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1060 if (obj == NULL) return;
1061#ifdef DEBUG
1062 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
1063#endif
1064 xmlFree(obj);
1065}
1066
1067/************************************************************************
1068 * *
1069 * Routines to handle extra functions *
1070 * *
1071 ************************************************************************/
1072
1073/**
1074 * xmlXPathRegisterFunc:
1075 * @ctxt: the XPath context
1076 * @name: the function name
1077 * @f: the function implementation or NULL
1078 *
1079 * Register a new function. If @f is NULL it unregisters the function
1080 *
1081 * Returns 0 in case of success, -1 in case of error
1082 */
1083int
1084xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1085 xmlXPathFunction f) {
1086 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1087}
1088
1089/**
1090 * xmlXPathRegisterFuncNS:
1091 * @ctxt: the XPath context
1092 * @name: the function name
1093 * @ns_uri: the function namespace URI
1094 * @f: the function implementation or NULL
1095 *
1096 * Register a new function. If @f is NULL it unregisters the function
1097 *
1098 * Returns 0 in case of success, -1 in case of error
1099 */
1100int
1101xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1102 const xmlChar *ns_uri, xmlXPathFunction f) {
1103 if (ctxt == NULL)
1104 return(-1);
1105 if (name == NULL)
1106 return(-1);
1107
1108 if (ctxt->funcHash == NULL)
1109 ctxt->funcHash = xmlHashCreate(0);
1110 if (ctxt->funcHash == NULL)
1111 return(-1);
1112 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1113}
1114
1115/**
1116 * xmlXPathFunctionLookup:
1117 * @ctxt: the XPath context
1118 * @name: the function name
1119 *
1120 * Search in the Function array of the context for the given
1121 * function.
1122 *
1123 * Returns the xmlXPathFunction or NULL if not found
1124 */
1125xmlXPathFunction
1126xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1127 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1128}
1129
1130/**
1131 * xmlXPathFunctionLookupNS:
1132 * @ctxt: the XPath context
1133 * @name: the function name
1134 * @ns_uri: the function namespace URI
1135 *
1136 * Search in the Function array of the context for the given
1137 * function.
1138 *
1139 * Returns the xmlXPathFunction or NULL if not found
1140 */
1141xmlXPathFunction
1142xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1143 const xmlChar *ns_uri) {
1144 if (ctxt == NULL)
1145 return(NULL);
1146 if (ctxt->funcHash == NULL)
1147 return(NULL);
1148 if (name == NULL)
1149 return(NULL);
1150
1151 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1152}
1153
1154/**
1155 * xmlXPathRegisteredFuncsCleanup:
1156 * @ctxt: the XPath context
1157 *
1158 * Cleanup the XPath context data associated to registered functions
1159 */
1160void
1161xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1162 if (ctxt == NULL)
1163 return;
1164
1165 xmlHashFree(ctxt->funcHash, NULL);
1166 ctxt->funcHash = NULL;
1167}
1168
1169/************************************************************************
1170 * *
1171 * Routines to handle Variable *
1172 * *
1173 ************************************************************************/
1174
1175/**
1176 * xmlXPathRegisterVariable:
1177 * @ctxt: the XPath context
1178 * @name: the variable name
1179 * @value: the variable value or NULL
1180 *
1181 * Register a new variable value. If @value is NULL it unregisters
1182 * the variable
1183 *
1184 * Returns 0 in case of success, -1 in case of error
1185 */
1186int
1187xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1188 xmlXPathObjectPtr value) {
1189 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1190}
1191
1192/**
1193 * xmlXPathRegisterVariableNS:
1194 * @ctxt: the XPath context
1195 * @name: the variable name
1196 * @ns_uri: the variable namespace URI
1197 * @value: the variable value or NULL
1198 *
1199 * Register a new variable value. If @value is NULL it unregisters
1200 * the variable
1201 *
1202 * Returns 0 in case of success, -1 in case of error
1203 */
1204int
1205xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1206 const xmlChar *ns_uri,
1207 xmlXPathObjectPtr value) {
1208 if (ctxt == NULL)
1209 return(-1);
1210 if (name == NULL)
1211 return(-1);
1212
1213 if (ctxt->varHash == NULL)
1214 ctxt->varHash = xmlHashCreate(0);
1215 if (ctxt->varHash == NULL)
1216 return(-1);
1217 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1218 (void *) value,
1219 (xmlHashDeallocator)xmlXPathFreeObject));
1220}
1221
1222/**
1223 * xmlXPathRegisterVariableLookup:
1224 * @ctxt: the XPath context
1225 * @f: the lookup function
1226 * @data: the lookup data
1227 *
1228 * register an external mechanism to do variable lookup
1229 */
1230void
1231xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1232 xmlXPathVariableLookupFunc f, void *data) {
1233 if (ctxt == NULL)
1234 return;
1235 ctxt->varLookupFunc = (void *) f;
1236 ctxt->varLookupData = data;
1237}
1238
1239/**
1240 * xmlXPathVariableLookup:
1241 * @ctxt: the XPath context
1242 * @name: the variable name
1243 *
1244 * Search in the Variable array of the context for the given
1245 * variable value.
1246 *
1247 * Returns the value or NULL if not found
1248 */
1249xmlXPathObjectPtr
1250xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1251 if (ctxt == NULL)
1252 return(NULL);
1253
1254 if (ctxt->varLookupFunc != NULL) {
1255 xmlXPathObjectPtr ret;
1256
1257 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1258 (ctxt->varLookupData, name, NULL);
1259 if (ret != NULL) return(ret);
1260 }
1261 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1262}
1263
1264/**
1265 * xmlXPathVariableLookupNS:
1266 * @ctxt: the XPath context
1267 * @name: the variable name
1268 * @ns_uri: the variable namespace URI
1269 *
1270 * Search in the Variable array of the context for the given
1271 * variable value.
1272 *
1273 * Returns the value or NULL if not found
1274 */
1275xmlXPathObjectPtr
1276xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1277 const xmlChar *ns_uri) {
1278 if (ctxt == NULL)
1279 return(NULL);
1280
1281 if (ctxt->varLookupFunc != NULL) {
1282 xmlXPathObjectPtr ret;
1283
1284 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1285 (ctxt->varLookupData, name, ns_uri);
1286 if (ret != NULL) return(ret);
1287 }
1288
1289 if (ctxt->varHash == NULL)
1290 return(NULL);
1291 if (name == NULL)
1292 return(NULL);
1293
1294 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1295}
1296
1297/**
1298 * xmlXPathRegisteredVariablesCleanup:
1299 * @ctxt: the XPath context
1300 *
1301 * Cleanup the XPath context data associated to registered variables
1302 */
1303void
1304xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1305 if (ctxt == NULL)
1306 return;
1307
1308 xmlHashFree(ctxt->varHash, NULL);
1309 ctxt->varHash = NULL;
1310}
1311
1312/**
1313 * xmlXPathRegisterNs:
1314 * @ctxt: the XPath context
1315 * @prefix: the namespace prefix
1316 * @ns_uri: the namespace name
1317 *
1318 * Register a new namespace. If @ns_uri is NULL it unregisters
1319 * the namespace
1320 *
1321 * Returns 0 in case of success, -1 in case of error
1322 */
1323int
1324xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1325 const xmlChar *ns_uri) {
1326 if (ctxt == NULL)
1327 return(-1);
1328 if (prefix == NULL)
1329 return(-1);
1330
1331 if (ctxt->nsHash == NULL)
1332 ctxt->nsHash = xmlHashCreate(10);
1333 if (ctxt->nsHash == NULL)
1334 return(-1);
1335 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1336 (xmlHashDeallocator)xmlFree));
1337}
1338
1339/**
1340 * xmlXPathNsLookup:
1341 * @ctxt: the XPath context
1342 * @prefix: the namespace prefix value
1343 *
1344 * Search in the namespace declaration array of the context for the given
1345 * namespace name associated to the given prefix
1346 *
1347 * Returns the value or NULL if not found
1348 */
1349const xmlChar *
1350xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1351 if (ctxt == NULL)
1352 return(NULL);
1353 if (prefix == NULL)
1354 return(NULL);
1355
1356#ifdef XML_XML_NAMESPACE
1357 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1358 return(XML_XML_NAMESPACE);
1359#endif
1360
1361 if (ctxt->nsHash == NULL)
1362 return(NULL);
1363
1364 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1365}
1366
1367/**
1368 * xmlXPathRegisteredVariablesCleanup:
1369 * @ctxt: the XPath context
1370 *
1371 * Cleanup the XPath context data associated to registered variables
1372 */
1373void
1374xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1375 if (ctxt == NULL)
1376 return;
1377
1378 xmlHashFree(ctxt->nsHash, NULL);
1379 ctxt->nsHash = NULL;
1380}
1381
1382/************************************************************************
1383 * *
1384 * Routines to handle Values *
1385 * *
1386 ************************************************************************/
1387
1388/* Allocations are terrible, one need to optimize all this !!! */
1389
1390/**
1391 * xmlXPathNewFloat:
1392 * @val: the double value
1393 *
1394 * Create a new xmlXPathObjectPtr of type double and of value @val
1395 *
1396 * Returns the newly created object.
1397 */
1398xmlXPathObjectPtr
1399xmlXPathNewFloat(double val) {
1400 xmlXPathObjectPtr ret;
1401
1402 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1403 if (ret == NULL) {
1404 xmlGenericError(xmlGenericErrorContext,
1405 "xmlXPathNewFloat: out of memory\n");
1406 return(NULL);
1407 }
1408 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1409 ret->type = XPATH_NUMBER;
1410 ret->floatval = val;
1411 return(ret);
1412}
1413
1414/**
1415 * xmlXPathNewBoolean:
1416 * @val: the boolean value
1417 *
1418 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1419 *
1420 * Returns the newly created object.
1421 */
1422xmlXPathObjectPtr
1423xmlXPathNewBoolean(int val) {
1424 xmlXPathObjectPtr ret;
1425
1426 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1427 if (ret == NULL) {
1428 xmlGenericError(xmlGenericErrorContext,
1429 "xmlXPathNewBoolean: out of memory\n");
1430 return(NULL);
1431 }
1432 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1433 ret->type = XPATH_BOOLEAN;
1434 ret->boolval = (val != 0);
1435 return(ret);
1436}
1437
1438/**
1439 * xmlXPathNewString:
1440 * @val: the xmlChar * value
1441 *
1442 * Create a new xmlXPathObjectPtr of type string and of value @val
1443 *
1444 * Returns the newly created object.
1445 */
1446xmlXPathObjectPtr
1447xmlXPathNewString(const xmlChar *val) {
1448 xmlXPathObjectPtr ret;
1449
1450 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1451 if (ret == NULL) {
1452 xmlGenericError(xmlGenericErrorContext,
1453 "xmlXPathNewString: out of memory\n");
1454 return(NULL);
1455 }
1456 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1457 ret->type = XPATH_STRING;
1458 if (val != NULL)
1459 ret->stringval = xmlStrdup(val);
1460 else
1461 ret->stringval = xmlStrdup((const xmlChar *)"");
1462 return(ret);
1463}
1464
1465/**
1466 * xmlXPathNewCString:
1467 * @val: the char * value
1468 *
1469 * Create a new xmlXPathObjectPtr of type string and of value @val
1470 *
1471 * Returns the newly created object.
1472 */
1473xmlXPathObjectPtr
1474xmlXPathNewCString(const char *val) {
1475 xmlXPathObjectPtr ret;
1476
1477 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1478 if (ret == NULL) {
1479 xmlGenericError(xmlGenericErrorContext,
1480 "xmlXPathNewCString: out of memory\n");
1481 return(NULL);
1482 }
1483 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1484 ret->type = XPATH_STRING;
1485 ret->stringval = xmlStrdup(BAD_CAST val);
1486 return(ret);
1487}
1488
1489/**
1490 * xmlXPathObjectCopy:
1491 * @val: the original object
1492 *
1493 * allocate a new copy of a given object
1494 *
1495 * Returns the newly created object.
1496 */
1497xmlXPathObjectPtr
1498xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1499 xmlXPathObjectPtr ret;
1500
1501 if (val == NULL)
1502 return(NULL);
1503
1504 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1505 if (ret == NULL) {
1506 xmlGenericError(xmlGenericErrorContext,
1507 "xmlXPathObjectCopy: out of memory\n");
1508 return(NULL);
1509 }
1510 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1511 switch (val->type) {
1512 case XPATH_BOOLEAN:
1513 case XPATH_NUMBER:
1514 case XPATH_POINT:
1515 case XPATH_RANGE:
1516 break;
1517 case XPATH_STRING:
1518 ret->stringval = xmlStrdup(val->stringval);
1519 break;
1520 case XPATH_XSLT_TREE:
1521 if ((val->nodesetval != NULL) &&
1522 (val->nodesetval->nodeTab != NULL))
1523 ret->nodesetval = xmlXPathNodeSetCreate(
1524 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
1525 else
1526 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
1527 break;
1528 case XPATH_NODESET:
1529 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1530 break;
1531 case XPATH_LOCATIONSET:
1532#ifdef LIBXML_XPTR_ENABLED
1533 {
1534 xmlLocationSetPtr loc = val->user;
1535 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1536 break;
1537 }
1538#endif
1539 case XPATH_UNDEFINED:
1540 case XPATH_USERS:
1541 xmlGenericError(xmlGenericErrorContext,
1542 "xmlXPathObjectCopy: unsupported type %d\n",
1543 val->type);
1544 break;
1545 }
1546 return(ret);
1547}
1548
1549/**
1550 * xmlXPathFreeObject:
1551 * @obj: the object to free
1552 *
1553 * Free up an xmlXPathObjectPtr object.
1554 */
1555void
1556xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1557 if (obj == NULL) return;
1558 if (obj->type == XPATH_NODESET) {
1559 if (obj->nodesetval != NULL)
1560 xmlXPathFreeNodeSet(obj->nodesetval);
1561#ifdef LIBXML_XPTR_ENABLED
1562 } else if (obj->type == XPATH_LOCATIONSET) {
1563 if (obj->user != NULL)
1564 xmlXPtrFreeLocationSet(obj->user);
1565#endif
1566 } else if (obj->type == XPATH_STRING) {
1567 if (obj->stringval != NULL)
1568 xmlFree(obj->stringval);
1569 } else if (obj->type == XPATH_XSLT_TREE) {
1570 if (obj->nodesetval != NULL)
1571 xmlXPathFreeValueTree(obj->nodesetval);
1572 }
1573
1574#ifdef DEBUG
1575 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
1576#endif
1577 xmlFree(obj);
1578}
1579
1580/************************************************************************
1581 * *
1582 * Routines to handle XPath contexts *
1583 * *
1584 ************************************************************************/
1585
1586/**
1587 * xmlXPathNewContext:
1588 * @doc: the XML document
1589 *
1590 * Create a new xmlXPathContext
1591 *
1592 * Returns the xmlXPathContext just allocated.
1593 */
1594xmlXPathContextPtr
1595xmlXPathNewContext(xmlDocPtr doc) {
1596 xmlXPathContextPtr ret;
1597
1598 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
1599 if (ret == NULL) {
1600 xmlGenericError(xmlGenericErrorContext,
1601 "xmlXPathNewContext: out of memory\n");
1602 return(NULL);
1603 }
1604 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
1605 ret->doc = doc;
1606 ret->node = NULL;
1607
1608 ret->varHash = NULL;
1609
1610 ret->nb_types = 0;
1611 ret->max_types = 0;
1612 ret->types = NULL;
1613
1614 ret->funcHash = xmlHashCreate(0);
1615
1616 ret->nb_axis = 0;
1617 ret->max_axis = 0;
1618 ret->axis = NULL;
1619
1620 ret->nsHash = NULL;
1621 ret->user = NULL;
1622
1623 ret->contextSize = -1;
1624 ret->proximityPosition = -1;
1625
1626 xmlXPathRegisterAllFunctions(ret);
1627
1628 return(ret);
1629}
1630
1631/**
1632 * xmlXPathFreeContext:
1633 * @ctxt: the context to free
1634 *
1635 * Free up an xmlXPathContext
1636 */
1637void
1638xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
1639 xmlXPathRegisteredNsCleanup(ctxt);
1640 xmlXPathRegisteredFuncsCleanup(ctxt);
1641 xmlXPathRegisteredVariablesCleanup(ctxt);
1642#ifdef DEBUG
1643 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
1644#endif
1645 xmlFree(ctxt);
1646}
1647
1648/************************************************************************
1649 * *
1650 * Routines to handle XPath parser contexts *
1651 * *
1652 ************************************************************************/
1653
1654#define CHECK_CTXT(ctxt) \
1655 if (ctxt == NULL) { \
1656 xmlGenericError(xmlGenericErrorContext, \
1657 "%s:%d Internal error: ctxt == NULL\n", \
1658 __FILE__, __LINE__); \
1659 } \
1660
1661
1662#define CHECK_CONTEXT(ctxt) \
1663 if (ctxt == NULL) { \
1664 xmlGenericError(xmlGenericErrorContext, \
1665 "%s:%d Internal error: no context\n", \
1666 __FILE__, __LINE__); \
1667 } \
1668 else if (ctxt->doc == NULL) { \
1669 xmlGenericError(xmlGenericErrorContext, \
1670 "%s:%d Internal error: no document\n", \
1671 __FILE__, __LINE__); \
1672 } \
1673 else if (ctxt->doc->children == NULL) { \
1674 xmlGenericError(xmlGenericErrorContext, \
1675 "%s:%d Internal error: document without root\n", \
1676 __FILE__, __LINE__); \
1677 } \
1678
1679
1680/**
1681 * xmlXPathNewParserContext:
1682 * @str: the XPath expression
1683 * @ctxt: the XPath context
1684 *
1685 * Create a new xmlXPathParserContext
1686 *
1687 * Returns the xmlXPathParserContext just allocated.
1688 */
1689xmlXPathParserContextPtr
1690xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
1691 xmlXPathParserContextPtr ret;
1692
1693 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
1694 if (ret == NULL) {
1695 xmlGenericError(xmlGenericErrorContext,
1696 "xmlXPathNewParserContext: out of memory\n");
1697 return(NULL);
1698 }
1699 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
1700 ret->cur = ret->base = str;
1701 ret->context = ctxt;
1702
1703 /* Allocate the value stack */
1704 ret->valueTab = (xmlXPathObjectPtr *)
1705 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
1706 ret->valueNr = 0;
1707 ret->valueMax = 10;
1708 ret->value = NULL;
1709 return(ret);
1710}
1711
1712/**
1713 * xmlXPathFreeParserContext:
1714 * @ctxt: the context to free
1715 *
1716 * Free up an xmlXPathParserContext
1717 */
1718void
1719xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1720 if (ctxt->valueTab != NULL) {
1721#ifdef DEBUG
1722 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
1723#endif
1724 xmlFree(ctxt->valueTab);
1725 }
1726#ifdef DEBUG
1727 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
1728#endif
1729 xmlFree(ctxt);
1730}
1731
1732/************************************************************************
1733 * *
1734 * The implicit core function library *
1735 * *
1736 ************************************************************************/
1737
1738/*
1739 * Auto-pop and cast to a number
1740 */
1741void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1742
1743
1744#define POP_FLOAT \
1745 arg = valuePop(ctxt); \
1746 if (arg == NULL) { \
1747 XP_ERROR(XPATH_INVALID_OPERAND); \
1748 } \
1749 if (arg->type != XPATH_NUMBER) { \
1750 valuePush(ctxt, arg); \
1751 xmlXPathNumberFunction(ctxt, 1); \
1752 arg = valuePop(ctxt); \
1753 }
1754
1755/**
1756 * xmlXPathCompareNodeSetFloat:
1757 * @ctxt: the XPath Parser context
1758 * @inf: less than (1) or greater than (0)
1759 * @strict: is the comparison strict
1760 * @arg: the node set
1761 * @f: the value
1762 *
1763 * Implement the compare operation between a nodeset and a number
1764 * @ns < @val (1, 1, ...
1765 * @ns <= @val (1, 0, ...
1766 * @ns > @val (0, 1, ...
1767 * @ns >= @val (0, 0, ...
1768 *
1769 * If one object to be compared is a node-set and the other is a number,
1770 * then the comparison will be true if and only if there is a node in the
1771 * node-set such that the result of performing the comparison on the number
1772 * to be compared and on the result of converting the string-value of that
1773 * node to a number using the number function is true.
1774 *
1775 * Returns 0 or 1 depending on the results of the test.
1776 */
1777int
1778xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
1779 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
1780 int i, ret = 0;
1781 xmlNodeSetPtr ns;
1782 xmlChar *str2;
1783
1784 if ((f == NULL) || (arg == NULL) ||
1785 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
1786 xmlXPathFreeObject(arg);
1787 xmlXPathFreeObject(f);
1788 return(0);
1789 }
1790 ns = arg->nodesetval;
1791 for (i = 0;i < ns->nodeNr;i++) {
1792 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1793 if (str2 != NULL) {
1794 valuePush(ctxt,
1795 xmlXPathNewString(str2));
1796 xmlFree(str2);
1797 xmlXPathNumberFunction(ctxt, 1);
1798 valuePush(ctxt, xmlXPathObjectCopy(f));
1799 ret = xmlXPathCompareValues(ctxt, inf, strict);
1800 if (ret)
1801 break;
1802 }
1803 }
1804 xmlXPathFreeObject(arg);
1805 xmlXPathFreeObject(f);
1806 return(ret);
1807}
1808
1809/**
1810 * xmlXPathCompareNodeSetString:
1811 * @ctxt: the XPath Parser context
1812 * @inf: less than (1) or greater than (0)
1813 * @strict: is the comparison strict
1814 * @arg: the node set
1815 * @s: the value
1816 *
1817 * Implement the compare operation between a nodeset and a string
1818 * @ns < @val (1, 1, ...
1819 * @ns <= @val (1, 0, ...
1820 * @ns > @val (0, 1, ...
1821 * @ns >= @val (0, 0, ...
1822 *
1823 * If one object to be compared is a node-set and the other is a string,
1824 * then the comparison will be true if and only if there is a node in
1825 * the node-set such that the result of performing the comparison on the
1826 * string-value of the node and the other string is true.
1827 *
1828 * Returns 0 or 1 depending on the results of the test.
1829 */
1830int
1831xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
1832 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
1833 int i, ret = 0;
1834 xmlNodeSetPtr ns;
1835 xmlChar *str2;
1836
1837 if ((s == NULL) || (arg == NULL) ||
1838 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
1839 xmlXPathFreeObject(arg);
1840 xmlXPathFreeObject(s);
1841 return(0);
1842 }
1843 ns = arg->nodesetval;
1844 for (i = 0;i < ns->nodeNr;i++) {
1845 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1846 if (str2 != NULL) {
1847 valuePush(ctxt,
1848 xmlXPathNewString(str2));
1849 xmlFree(str2);
1850 valuePush(ctxt, xmlXPathObjectCopy(s));
1851 ret = xmlXPathCompareValues(ctxt, inf, strict);
1852 if (ret)
1853 break;
1854 }
1855 }
1856 xmlXPathFreeObject(arg);
1857 xmlXPathFreeObject(s);
1858 return(ret);
1859}
1860
1861/**
1862 * xmlXPathCompareNodeSets:
1863 * @ctxt: the XPath Parser context
1864 * @op: less than (-1), equal (0) or greater than (1)
1865 * @strict: is the comparison strict
1866 * @arg1: the fist node set object
1867 * @arg2: the second node set object
1868 *
1869 * Implement the compare operation on nodesets:
1870 *
1871 * If both objects to be compared are node-sets, then the comparison
1872 * will be true if and only if there is a node in the first node-set
1873 * and a node in the second node-set such that the result of performing
1874 * the comparison on the string-values of the two nodes is true.
1875 * ....
1876 * When neither object to be compared is a node-set and the operator
1877 * is <=, <, >= or >, then the objects are compared by converting both
1878 * objects to numbers and comparing the numbers according to IEEE 754.
1879 * ....
1880 * The number function converts its argument to a number as follows:
1881 * - a string that consists of optional whitespace followed by an
1882 * optional minus sign followed by a Number followed by whitespace
1883 * is converted to the IEEE 754 number that is nearest (according
1884 * to the IEEE 754 round-to-nearest rule) to the mathematical value
1885 * represented by the string; any other string is converted to NaN
1886 *
1887 * Conclusion all nodes need to be converted first to their string value
1888 * and then the comparison must be done when possible
1889 */
1890int
1891xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
1892 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1893 int i, j, init = 0;
1894 double val1;
1895 double *values2;
1896 int ret = 0;
1897 xmlChar *str;
1898 xmlNodeSetPtr ns1;
1899 xmlNodeSetPtr ns2;
1900
1901 if ((arg1 == NULL) ||
1902 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
1903 return(0);
1904 if ((arg2 == NULL) ||
1905 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
1906 return(0);
1907
1908 ns1 = arg1->nodesetval;
1909 ns2 = arg2->nodesetval;
1910
1911 if (ns1->nodeNr <= 0)
1912 return(0);
1913 if (ns2->nodeNr <= 0)
1914 return(0);
1915
1916 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
1917 if (values2 == NULL) {
1918 return(0);
1919 }
1920 for (i = 0;i < ns1->nodeNr;i++) {
1921 str = xmlNodeGetContent(ns1->nodeTab[i]);
1922 if (str == NULL)
1923 continue;
1924 val1 = xmlXPathStringEvalNumber(str);
1925 xmlFree(str);
1926 if (isnan(val1))
1927 continue;
1928 for (j = 0;j < ns2->nodeNr;j++) {
1929 if (init == 0) {
1930 str = xmlNodeGetContent(ns2->nodeTab[j]);
1931 if (str == NULL) {
1932 values2[j] = xmlXPathNAN;
1933 } else {
1934 values2[j] = xmlXPathStringEvalNumber(str);
1935 xmlFree(str);
1936 }
1937 }
1938 if (isnan(values2[j]))
1939 continue;
1940 if (inf && strict)
1941 ret = (val1 < values2[j]);
1942 else if (inf && !strict)
1943 ret = (val1 <= values2[j]);
1944 else if (!inf && strict)
1945 ret = (val1 > values2[j]);
1946 else if (!inf && !strict)
1947 ret = (val1 >= values2[j]);
1948 if (ret)
1949 break;
1950 }
1951 if (ret)
1952 break;
1953 init = 1;
1954 }
1955 xmlFree(values2);
1956 return(ret);
1957 return(0);
1958}
1959
1960/**
1961 * xmlXPathCompareNodeSetValue:
1962 * @ctxt: the XPath Parser context
1963 * @inf: less than (1) or greater than (0)
1964 * @strict: is the comparison strict
1965 * @arg: the node set
1966 * @val: the value
1967 *
1968 * Implement the compare operation between a nodeset and a value
1969 * @ns < @val (1, 1, ...
1970 * @ns <= @val (1, 0, ...
1971 * @ns > @val (0, 1, ...
1972 * @ns >= @val (0, 0, ...
1973 *
1974 * If one object to be compared is a node-set and the other is a boolean,
1975 * then the comparison will be true if and only if the result of performing
1976 * the comparison on the boolean and on the result of converting
1977 * the node-set to a boolean using the boolean function is true.
1978 *
1979 * Returns 0 or 1 depending on the results of the test.
1980 */
1981int
1982xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
1983 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
1984 if ((val == NULL) || (arg == NULL) ||
1985 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
1986 return(0);
1987
1988 switch(val->type) {
1989 case XPATH_NUMBER:
1990 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
1991 case XPATH_NODESET:
1992 case XPATH_XSLT_TREE:
1993 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
1994 case XPATH_STRING:
1995 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
1996 case XPATH_BOOLEAN:
1997 valuePush(ctxt, arg);
1998 xmlXPathBooleanFunction(ctxt, 1);
1999 valuePush(ctxt, val);
2000 return(xmlXPathCompareValues(ctxt, inf, strict));
2001 default:
2002 TODO
2003 return(0);
2004 }
2005 return(0);
2006}
2007
2008/**
2009 * xmlXPathEqualNodeSetString
2010 * @arg: the nodeset object argument
2011 * @str: the string to compare to.
2012 *
2013 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2014 * If one object to be compared is a node-set and the other is a string,
2015 * then the comparison will be true if and only if there is a node in
2016 * the node-set such that the result of performing the comparison on the
2017 * string-value of the node and the other string is true.
2018 *
2019 * Returns 0 or 1 depending on the results of the test.
2020 */
2021int
2022xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
2023 int i;
2024 xmlNodeSetPtr ns;
2025 xmlChar *str2;
2026
2027 if ((str == NULL) || (arg == NULL) ||
2028 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2029 return(0);
2030 ns = arg->nodesetval;
2031 if (ns->nodeNr <= 0)
2032 return(0);
2033 for (i = 0;i < ns->nodeNr;i++) {
2034 str2 = xmlNodeGetContent(ns->nodeTab[i]);
2035 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
2036 xmlFree(str2);
2037 return(1);
2038 }
2039 if (str2 != NULL)
2040 xmlFree(str2);
2041 }
2042 return(0);
2043}
2044
2045/**
2046 * xmlXPathEqualNodeSetFloat
2047 * @arg: the nodeset object argument
2048 * @f: the float to compare to
2049 *
2050 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2051 * If one object to be compared is a node-set and the other is a number,
2052 * then the comparison will be true if and only if there is a node in
2053 * the node-set such that the result of performing the comparison on the
2054 * number to be compared and on the result of converting the string-value
2055 * of that node to a number using the number function is true.
2056 *
2057 * Returns 0 or 1 depending on the results of the test.
2058 */
2059int
2060xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
2061 char buf[100] = "";
2062
2063 if ((arg == NULL) ||
2064 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
2065 return(0);
2066
2067 if (isnan(f))
2068 sprintf(buf, "NaN");
2069 else if (isinf(f) > 0)
2070 sprintf(buf, "+Infinity");
2071 else if (isinf(f) < 0)
2072 sprintf(buf, "-Infinity");
2073 else
2074 sprintf(buf, "%0g", f);
2075
2076 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
2077}
2078
2079
2080/**
2081 * xmlXPathEqualNodeSets
2082 * @arg1: first nodeset object argument
2083 * @arg2: second nodeset object argument
2084 *
2085 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
2086 * If both objects to be compared are node-sets, then the comparison
2087 * will be true if and only if there is a node in the first node-set and
2088 * a node in the second node-set such that the result of performing the
2089 * comparison on the string-values of the two nodes is true.
2090 *
2091 * (needless to say, this is a costly operation)
2092 *
2093 * Returns 0 or 1 depending on the results of the test.
2094 */
2095int
2096xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2097 int i, j;
2098 xmlChar **values1;
2099 xmlChar **values2;
2100 int ret = 0;
2101 xmlNodeSetPtr ns1;
2102 xmlNodeSetPtr ns2;
2103
2104 if ((arg1 == NULL) ||
2105 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
2106 return(0);
2107 if ((arg2 == NULL) ||
2108 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
2109 return(0);
2110
2111 ns1 = arg1->nodesetval;
2112 ns2 = arg2->nodesetval;
2113
2114 if (ns1->nodeNr <= 0)
2115 return(0);
2116 if (ns2->nodeNr <= 0)
2117 return(0);
2118
2119 /*
2120 * check if there is a node pertaining to both sets
2121 */
2122 for (i = 0;i < ns1->nodeNr;i++)
2123 for (j = 0;j < ns2->nodeNr;j++)
2124 if (ns1->nodeTab[i] == ns2->nodeTab[j])
2125 return(1);
2126
2127 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
2128 if (values1 == NULL)
2129 return(0);
2130 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
2131 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
2132 if (values2 == NULL) {
2133 xmlFree(values1);
2134 return(0);
2135 }
2136 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
2137 for (i = 0;i < ns1->nodeNr;i++) {
2138 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
2139 for (j = 0;j < ns2->nodeNr;j++) {
2140 if (i == 0)
2141 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
2142 ret = xmlStrEqual(values1[i], values2[j]);
2143 if (ret)
2144 break;
2145 }
2146 if (ret)
2147 break;
2148 }
2149 for (i = 0;i < ns1->nodeNr;i++)
2150 if (values1[i] != NULL)
2151 xmlFree(values1[i]);
2152 for (j = 0;j < ns2->nodeNr;j++)
2153 if (values2[j] != NULL)
2154 xmlFree(values2[j]);
2155 xmlFree(values1);
2156 xmlFree(values2);
2157 return(ret);
2158}
2159
2160/**
2161 * xmlXPathEqualValues:
2162 * @ctxt: the XPath Parser context
2163 *
2164 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2165 *
2166 * Returns 0 or 1 depending on the results of the test.
2167 */
2168int
2169xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2170 xmlXPathObjectPtr arg1, arg2;
2171 int ret = 0;
2172
2173 arg1 = valuePop(ctxt);
2174 if (arg1 == NULL)
2175 XP_ERROR0(XPATH_INVALID_OPERAND);
2176
2177 arg2 = valuePop(ctxt);
2178 if (arg2 == NULL) {
2179 xmlXPathFreeObject(arg1);
2180 XP_ERROR0(XPATH_INVALID_OPERAND);
2181 }
2182
2183 if (arg1 == arg2) {
2184#ifdef DEBUG_EXPR
2185 xmlGenericError(xmlGenericErrorContext,
2186 "Equal: by pointer\n");
2187#endif
2188 return(1);
2189 }
2190
2191 switch (arg1->type) {
2192 case XPATH_UNDEFINED:
2193#ifdef DEBUG_EXPR
2194 xmlGenericError(xmlGenericErrorContext,
2195 "Equal: undefined\n");
2196#endif
2197 break;
2198 case XPATH_XSLT_TREE:
2199 case XPATH_NODESET:
2200 switch (arg2->type) {
2201 case XPATH_UNDEFINED:
2202#ifdef DEBUG_EXPR
2203 xmlGenericError(xmlGenericErrorContext,
2204 "Equal: undefined\n");
2205#endif
2206 break;
2207 case XPATH_XSLT_TREE:
2208 case XPATH_NODESET:
2209 ret = xmlXPathEqualNodeSets(arg1, arg2);
2210 break;
2211 case XPATH_BOOLEAN:
2212 if ((arg1->nodesetval == NULL) ||
2213 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2214 else
2215 ret = 1;
2216 ret = (ret == arg2->boolval);
2217 break;
2218 case XPATH_NUMBER:
2219 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2220 break;
2221 case XPATH_STRING:
2222 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2223 break;
2224 case XPATH_USERS:
2225 case XPATH_POINT:
2226 case XPATH_RANGE:
2227 case XPATH_LOCATIONSET:
2228 TODO
2229 break;
2230 }
2231 break;
2232 case XPATH_BOOLEAN:
2233 switch (arg2->type) {
2234 case XPATH_UNDEFINED:
2235#ifdef DEBUG_EXPR
2236 xmlGenericError(xmlGenericErrorContext,
2237 "Equal: undefined\n");
2238#endif
2239 break;
2240 case XPATH_NODESET:
2241 case XPATH_XSLT_TREE:
2242 if ((arg2->nodesetval == NULL) ||
2243 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2244 else
2245 ret = 1;
2246 break;
2247 case XPATH_BOOLEAN:
2248#ifdef DEBUG_EXPR
2249 xmlGenericError(xmlGenericErrorContext,
2250 "Equal: %d boolean %d \n",
2251 arg1->boolval, arg2->boolval);
2252#endif
2253 ret = (arg1->boolval == arg2->boolval);
2254 break;
2255 case XPATH_NUMBER:
2256 if (arg2->floatval) ret = 1;
2257 else ret = 0;
2258 ret = (arg1->boolval == ret);
2259 break;
2260 case XPATH_STRING:
2261 if ((arg2->stringval == NULL) ||
2262 (arg2->stringval[0] == 0)) ret = 0;
2263 else
2264 ret = 1;
2265 ret = (arg1->boolval == ret);
2266 break;
2267 case XPATH_USERS:
2268 case XPATH_POINT:
2269 case XPATH_RANGE:
2270 case XPATH_LOCATIONSET:
2271 TODO
2272 break;
2273 }
2274 break;
2275 case XPATH_NUMBER:
2276 switch (arg2->type) {
2277 case XPATH_UNDEFINED:
2278#ifdef DEBUG_EXPR
2279 xmlGenericError(xmlGenericErrorContext,
2280 "Equal: undefined\n");
2281#endif
2282 break;
2283 case XPATH_NODESET:
2284 case XPATH_XSLT_TREE:
2285 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2286 break;
2287 case XPATH_BOOLEAN:
2288 if (arg1->floatval) ret = 1;
2289 else ret = 0;
2290 ret = (arg2->boolval == ret);
2291 break;
2292 case XPATH_STRING:
2293 valuePush(ctxt, arg2);
2294 xmlXPathNumberFunction(ctxt, 1);
2295 arg2 = valuePop(ctxt);
2296 /* no break on purpose */
2297 case XPATH_NUMBER:
2298 ret = (arg1->floatval == arg2->floatval);
2299 break;
2300 case XPATH_USERS:
2301 case XPATH_POINT:
2302 case XPATH_RANGE:
2303 case XPATH_LOCATIONSET:
2304 TODO
2305 break;
2306 }
2307 break;
2308 case XPATH_STRING:
2309 switch (arg2->type) {
2310 case XPATH_UNDEFINED:
2311#ifdef DEBUG_EXPR
2312 xmlGenericError(xmlGenericErrorContext,
2313 "Equal: undefined\n");
2314#endif
2315 break;
2316 case XPATH_NODESET:
2317 case XPATH_XSLT_TREE:
2318 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2319 break;
2320 case XPATH_BOOLEAN:
2321 if ((arg1->stringval == NULL) ||
2322 (arg1->stringval[0] == 0)) ret = 0;
2323 else
2324 ret = 1;
2325 ret = (arg2->boolval == ret);
2326 break;
2327 case XPATH_STRING:
2328 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
2329 break;
2330 case XPATH_NUMBER:
2331 valuePush(ctxt, arg1);
2332 xmlXPathNumberFunction(ctxt, 1);
2333 arg1 = valuePop(ctxt);
2334 ret = (arg1->floatval == arg2->floatval);
2335 break;
2336 case XPATH_USERS:
2337 case XPATH_POINT:
2338 case XPATH_RANGE:
2339 case XPATH_LOCATIONSET:
2340 TODO
2341 break;
2342 }
2343 break;
2344 case XPATH_USERS:
2345 case XPATH_POINT:
2346 case XPATH_RANGE:
2347 case XPATH_LOCATIONSET:
2348 TODO
2349 break;
2350 }
2351 xmlXPathFreeObject(arg1);
2352 xmlXPathFreeObject(arg2);
2353 return(ret);
2354}
2355
2356
2357/**
2358 * xmlXPathCompareValues:
2359 * @ctxt: the XPath Parser context
2360 * @inf: less than (1) or greater than (0)
2361 * @strict: is the comparison strict
2362 *
2363 * Implement the compare operation on XPath objects:
2364 * @arg1 < @arg2 (1, 1, ...
2365 * @arg1 <= @arg2 (1, 0, ...
2366 * @arg1 > @arg2 (0, 1, ...
2367 * @arg1 >= @arg2 (0, 0, ...
2368 *
2369 * When neither object to be compared is a node-set and the operator is
2370 * <=, <, >=, >, then the objects are compared by converted both objects
2371 * to numbers and comparing the numbers according to IEEE 754. The <
2372 * comparison will be true if and only if the first number is less than the
2373 * second number. The <= comparison will be true if and only if the first
2374 * number is less than or equal to the second number. The > comparison
2375 * will be true if and only if the first number is greater than the second
2376 * number. The >= comparison will be true if and only if the first number
2377 * is greater than or equal to the second number.
2378 *
2379 * Returns 1 if the comparaison succeeded, 0 if it failed
2380 */
2381int
2382xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
2383 int ret = 0;
2384 xmlXPathObjectPtr arg1, arg2;
2385
2386 arg2 = valuePop(ctxt);
2387 if (arg2 == NULL) {
2388 XP_ERROR0(XPATH_INVALID_OPERAND);
2389 }
2390
2391 arg1 = valuePop(ctxt);
2392 if (arg1 == NULL) {
2393 xmlXPathFreeObject(arg2);
2394 XP_ERROR0(XPATH_INVALID_OPERAND);
2395 }
2396
2397 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
2398 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
2399 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
2400 } else {
2401 if (arg1->type == XPATH_NODESET) {
2402 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, arg1, arg2);
2403 } else {
2404 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, !strict, arg2, arg2);
2405 }
2406 }
2407 return(ret);
2408 }
2409
2410 if (arg1->type != XPATH_NUMBER) {
2411 valuePush(ctxt, arg1);
2412 xmlXPathNumberFunction(ctxt, 1);
2413 arg1 = valuePop(ctxt);
2414 }
2415 if (arg1->type != XPATH_NUMBER) {
2416 xmlXPathFreeObject(arg1);
2417 xmlXPathFreeObject(arg2);
2418 XP_ERROR0(XPATH_INVALID_OPERAND);
2419 }
2420 if (arg2->type != XPATH_NUMBER) {
2421 valuePush(ctxt, arg2);
2422 xmlXPathNumberFunction(ctxt, 1);
2423 arg2 = valuePop(ctxt);
2424 }
2425 if (arg2->type != XPATH_NUMBER) {
2426 xmlXPathFreeObject(arg1);
2427 xmlXPathFreeObject(arg2);
2428 XP_ERROR0(XPATH_INVALID_OPERAND);
2429 }
2430 /*
2431 * Add tests for infinity and nan
2432 * => feedback on 3.4 for Inf and NaN
2433 */
2434 if (inf && strict)
2435 ret = (arg1->floatval < arg2->floatval);
2436 else if (inf && !strict)
2437 ret = (arg1->floatval <= arg2->floatval);
2438 else if (!inf && strict)
2439 ret = (arg1->floatval > arg2->floatval);
2440 else if (!inf && !strict)
2441 ret = (arg1->floatval >= arg2->floatval);
2442 xmlXPathFreeObject(arg1);
2443 xmlXPathFreeObject(arg2);
2444 return(ret);
2445}
2446
2447/**
2448 * xmlXPathValueFlipSign:
2449 * @ctxt: the XPath Parser context
2450 *
2451 * Implement the unary - operation on an XPath object
2452 * The numeric operators convert their operands to numbers as if
2453 * by calling the number function.
2454 */
2455void
2456xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
2457 xmlXPathObjectPtr arg;
2458
2459 POP_FLOAT
2460 arg->floatval = -arg->floatval;
2461 valuePush(ctxt, arg);
2462}
2463
2464/**
2465 * xmlXPathAddValues:
2466 * @ctxt: the XPath Parser context
2467 *
2468 * Implement the add operation on XPath objects:
2469 * The numeric operators convert their operands to numbers as if
2470 * by calling the number function.
2471 */
2472void
2473xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
2474 xmlXPathObjectPtr arg;
2475 double val;
2476
2477 POP_FLOAT
2478 val = arg->floatval;
2479 xmlXPathFreeObject(arg);
2480
2481 POP_FLOAT
2482 arg->floatval += val;
2483 valuePush(ctxt, arg);
2484}
2485
2486/**
2487 * xmlXPathSubValues:
2488 * @ctxt: the XPath Parser context
2489 *
2490 * Implement the substraction operation on XPath objects:
2491 * The numeric operators convert their operands to numbers as if
2492 * by calling the number function.
2493 */
2494void
2495xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
2496 xmlXPathObjectPtr arg;
2497 double val;
2498
2499 POP_FLOAT
2500 val = arg->floatval;
2501 xmlXPathFreeObject(arg);
2502
2503 POP_FLOAT
2504 arg->floatval -= val;
2505 valuePush(ctxt, arg);
2506}
2507
2508/**
2509 * xmlXPathMultValues:
2510 * @ctxt: the XPath Parser context
2511 *
2512 * Implement the multiply operation on XPath objects:
2513 * The numeric operators convert their operands to numbers as if
2514 * by calling the number function.
2515 */
2516void
2517xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
2518 xmlXPathObjectPtr arg;
2519 double val;
2520
2521 POP_FLOAT
2522 val = arg->floatval;
2523 xmlXPathFreeObject(arg);
2524
2525 POP_FLOAT
2526 arg->floatval *= val;
2527 valuePush(ctxt, arg);
2528}
2529
2530/**
2531 * xmlXPathDivValues:
2532 * @ctxt: the XPath Parser context
2533 *
2534 * Implement the div operation on XPath objects @arg1 / @arg2:
2535 * The numeric operators convert their operands to numbers as if
2536 * by calling the number function.
2537 */
2538void
2539xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
2540 xmlXPathObjectPtr arg;
2541 double val;
2542
2543 POP_FLOAT
2544 val = arg->floatval;
2545 xmlXPathFreeObject(arg);
2546
2547 POP_FLOAT
2548 arg->floatval /= val;
2549 valuePush(ctxt, arg);
2550}
2551
2552/**
2553 * xmlXPathModValues:
2554 * @ctxt: the XPath Parser context
2555 *
2556 * Implement the mod operation on XPath objects: @arg1 / @arg2
2557 * The numeric operators convert their operands to numbers as if
2558 * by calling the number function.
2559 */
2560void
2561xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
2562 xmlXPathObjectPtr arg;
2563 int arg1, arg2;
2564
2565 POP_FLOAT
2566 arg2 = (int) arg->floatval;
2567 xmlXPathFreeObject(arg);
2568
2569 POP_FLOAT
2570 arg1 = (int) arg->floatval;
2571 arg->floatval = arg1 % arg2;
2572 valuePush(ctxt, arg);
2573}
2574
2575/************************************************************************
2576 * *
2577 * The traversal functions *
2578 * *
2579 ************************************************************************/
2580
2581typedef enum {
2582 AXIS_ANCESTOR = 1,
2583 AXIS_ANCESTOR_OR_SELF,
2584 AXIS_ATTRIBUTE,
2585 AXIS_CHILD,
2586 AXIS_DESCENDANT,
2587 AXIS_DESCENDANT_OR_SELF,
2588 AXIS_FOLLOWING,
2589 AXIS_FOLLOWING_SIBLING,
2590 AXIS_NAMESPACE,
2591 AXIS_PARENT,
2592 AXIS_PRECEDING,
2593 AXIS_PRECEDING_SIBLING,
2594 AXIS_SELF
2595} xmlXPathAxisVal;
2596
2597/*
2598 * A traversal function enumerates nodes along an axis.
2599 * Initially it must be called with NULL, and it indicates
2600 * termination on the axis by returning NULL.
2601 */
2602typedef xmlNodePtr (*xmlXPathTraversalFunction)
2603 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
2604
2605/**
2606 * xmlXPathNextSelf:
2607 * @ctxt: the XPath Parser context
2608 * @cur: the current node in the traversal
2609 *
2610 * Traversal function for the "self" direction
2611 * The self axis contains just the context node itself
2612 *
2613 * Returns the next element following that axis
2614 */
2615xmlNodePtr
2616xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2617 if (cur == NULL)
2618 return(ctxt->context->node);
2619 return(NULL);
2620}
2621
2622/**
2623 * xmlXPathNextChild:
2624 * @ctxt: the XPath Parser context
2625 * @cur: the current node in the traversal
2626 *
2627 * Traversal function for the "child" direction
2628 * The child axis contains the children of the context node in document order.
2629 *
2630 * Returns the next element following that axis
2631 */
2632xmlNodePtr
2633xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2634 if (cur == NULL) {
2635 if (ctxt->context->node == NULL) return(NULL);
2636 switch (ctxt->context->node->type) {
2637 case XML_ELEMENT_NODE:
2638 case XML_TEXT_NODE:
2639 case XML_CDATA_SECTION_NODE:
2640 case XML_ENTITY_REF_NODE:
2641 case XML_ENTITY_NODE:
2642 case XML_PI_NODE:
2643 case XML_COMMENT_NODE:
2644 case XML_NOTATION_NODE:
2645 case XML_DTD_NODE:
2646 return(ctxt->context->node->children);
2647 case XML_DOCUMENT_NODE:
2648 case XML_DOCUMENT_TYPE_NODE:
2649 case XML_DOCUMENT_FRAG_NODE:
2650 case XML_HTML_DOCUMENT_NODE:
2651#ifdef LIBXML_SGML_ENABLED
2652 case XML_SGML_DOCUMENT_NODE:
2653#endif
2654 return(((xmlDocPtr) ctxt->context->node)->children);
2655 case XML_ELEMENT_DECL:
2656 case XML_ATTRIBUTE_DECL:
2657 case XML_ENTITY_DECL:
2658 case XML_ATTRIBUTE_NODE:
2659 case XML_NAMESPACE_DECL:
2660 case XML_XINCLUDE_START:
2661 case XML_XINCLUDE_END:
2662 return(NULL);
2663 }
2664 return(NULL);
2665 }
2666 if ((cur->type == XML_DOCUMENT_NODE) ||
2667 (cur->type == XML_HTML_DOCUMENT_NODE))
2668 return(NULL);
2669 return(cur->next);
2670}
2671
2672/**
2673 * xmlXPathNextDescendant:
2674 * @ctxt: the XPath Parser context
2675 * @cur: the current node in the traversal
2676 *
2677 * Traversal function for the "descendant" direction
2678 * the descendant axis contains the descendants of the context node in document
2679 * order; a descendant is a child or a child of a child and so on.
2680 *
2681 * Returns the next element following that axis
2682 */
2683xmlNodePtr
2684xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2685 if (cur == NULL) {
2686 if (ctxt->context->node == NULL)
2687 return(NULL);
2688 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2689 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2690 return(NULL);
2691
2692 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2693 return(ctxt->context->doc->children);
2694 return(ctxt->context->node->children);
2695 }
2696
2697 if (cur->children != NULL)
2698 {
2699 if (cur->children->type != XML_ENTITY_DECL)
2700 return(cur->children);
2701 }
2702 if (cur->next != NULL) return(cur->next);
2703
2704 do {
2705 cur = cur->parent;
2706 if (cur == NULL) return(NULL);
2707 if (cur == ctxt->context->node) return(NULL);
2708 if (cur->next != NULL) {
2709 cur = cur->next;
2710 return(cur);
2711 }
2712 } while (cur != NULL);
2713 return(cur);
2714}
2715
2716/**
2717 * xmlXPathNextDescendantOrSelf:
2718 * @ctxt: the XPath Parser context
2719 * @cur: the current node in the traversal
2720 *
2721 * Traversal function for the "descendant-or-self" direction
2722 * the descendant-or-self axis contains the context node and the descendants
2723 * of the context node in document order; thus the context node is the first
2724 * node on the axis, and the first child of the context node is the second node
2725 * on the axis
2726 *
2727 * Returns the next element following that axis
2728 */
2729xmlNodePtr
2730xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2731 if (cur == NULL) {
2732 if (ctxt->context->node == NULL)
2733 return(NULL);
2734 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2735 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2736 return(NULL);
2737 return(ctxt->context->node);
2738 }
2739
2740 return(xmlXPathNextDescendant(ctxt, cur));
2741}
2742
2743/**
2744 * xmlXPathNextParent:
2745 * @ctxt: the XPath Parser context
2746 * @cur: the current node in the traversal
2747 *
2748 * Traversal function for the "parent" direction
2749 * The parent axis contains the parent of the context node, if there is one.
2750 *
2751 * Returns the next element following that axis
2752 */
2753xmlNodePtr
2754xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2755 /*
2756 * the parent of an attribute or namespace node is the element
2757 * to which the attribute or namespace node is attached
2758 * Namespace handling !!!
2759 */
2760 if (cur == NULL) {
2761 if (ctxt->context->node == NULL) return(NULL);
2762 switch (ctxt->context->node->type) {
2763 case XML_ELEMENT_NODE:
2764 case XML_TEXT_NODE:
2765 case XML_CDATA_SECTION_NODE:
2766 case XML_ENTITY_REF_NODE:
2767 case XML_ENTITY_NODE:
2768 case XML_PI_NODE:
2769 case XML_COMMENT_NODE:
2770 case XML_NOTATION_NODE:
2771 case XML_DTD_NODE:
2772 case XML_ELEMENT_DECL:
2773 case XML_ATTRIBUTE_DECL:
2774 case XML_XINCLUDE_START:
2775 case XML_XINCLUDE_END:
2776 case XML_ENTITY_DECL:
2777 if (ctxt->context->node->parent == NULL)
2778 return((xmlNodePtr) ctxt->context->doc);
2779 return(ctxt->context->node->parent);
2780 case XML_ATTRIBUTE_NODE: {
2781 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2782
2783 return(att->parent);
2784 }
2785 case XML_DOCUMENT_NODE:
2786 case XML_DOCUMENT_TYPE_NODE:
2787 case XML_DOCUMENT_FRAG_NODE:
2788 case XML_HTML_DOCUMENT_NODE:
2789#ifdef LIBXML_SGML_ENABLED
2790 case XML_SGML_DOCUMENT_NODE:
2791#endif
2792 return(NULL);
2793 case XML_NAMESPACE_DECL:
2794 /*
2795 * TODO !!! may require extending struct _xmlNs with
2796 * parent field
2797 * C.f. Infoset case...
2798 */
2799 return(NULL);
2800 }
2801 }
2802 return(NULL);
2803}
2804
2805/**
2806 * xmlXPathNextAncestor:
2807 * @ctxt: the XPath Parser context
2808 * @cur: the current node in the traversal
2809 *
2810 * Traversal function for the "ancestor" direction
2811 * the ancestor axis contains the ancestors of the context node; the ancestors
2812 * of the context node consist of the parent of context node and the parent's
2813 * parent and so on; the nodes are ordered in reverse document order; thus the
2814 * parent is the first node on the axis, and the parent's parent is the second
2815 * node on the axis
2816 *
2817 * Returns the next element following that axis
2818 */
2819xmlNodePtr
2820xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2821 /*
2822 * the parent of an attribute or namespace node is the element
2823 * to which the attribute or namespace node is attached
2824 * !!!!!!!!!!!!!
2825 */
2826 if (cur == NULL) {
2827 if (ctxt->context->node == NULL) return(NULL);
2828 switch (ctxt->context->node->type) {
2829 case XML_ELEMENT_NODE:
2830 case XML_TEXT_NODE:
2831 case XML_CDATA_SECTION_NODE:
2832 case XML_ENTITY_REF_NODE:
2833 case XML_ENTITY_NODE:
2834 case XML_PI_NODE:
2835 case XML_COMMENT_NODE:
2836 case XML_DTD_NODE:
2837 case XML_ELEMENT_DECL:
2838 case XML_ATTRIBUTE_DECL:
2839 case XML_ENTITY_DECL:
2840 case XML_NOTATION_NODE:
2841 case XML_XINCLUDE_START:
2842 case XML_XINCLUDE_END:
2843 if (ctxt->context->node->parent == NULL)
2844 return((xmlNodePtr) ctxt->context->doc);
2845 return(ctxt->context->node->parent);
2846 case XML_ATTRIBUTE_NODE: {
2847 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2848
2849 return(cur->parent);
2850 }
2851 case XML_DOCUMENT_NODE:
2852 case XML_DOCUMENT_TYPE_NODE:
2853 case XML_DOCUMENT_FRAG_NODE:
2854 case XML_HTML_DOCUMENT_NODE:
2855#ifdef LIBXML_SGML_ENABLED
2856 case XML_SGML_DOCUMENT_NODE:
2857#endif
2858 return(NULL);
2859 case XML_NAMESPACE_DECL:
2860 /*
2861 * TODO !!! may require extending struct _xmlNs with
2862 * parent field
2863 * C.f. Infoset case...
2864 */
2865 return(NULL);
2866 }
2867 return(NULL);
2868 }
2869 if (cur == ctxt->context->doc->children)
2870 return((xmlNodePtr) ctxt->context->doc);
2871 if (cur == (xmlNodePtr) ctxt->context->doc)
2872 return(NULL);
2873 switch (cur->type) {
2874 case XML_ELEMENT_NODE:
2875 case XML_TEXT_NODE:
2876 case XML_CDATA_SECTION_NODE:
2877 case XML_ENTITY_REF_NODE:
2878 case XML_ENTITY_NODE:
2879 case XML_PI_NODE:
2880 case XML_COMMENT_NODE:
2881 case XML_NOTATION_NODE:
2882 case XML_DTD_NODE:
2883 case XML_ELEMENT_DECL:
2884 case XML_ATTRIBUTE_DECL:
2885 case XML_ENTITY_DECL:
2886 case XML_XINCLUDE_START:
2887 case XML_XINCLUDE_END:
2888 return(cur->parent);
2889 case XML_ATTRIBUTE_NODE: {
2890 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2891
2892 return(att->parent);
2893 }
2894 case XML_DOCUMENT_NODE:
2895 case XML_DOCUMENT_TYPE_NODE:
2896 case XML_DOCUMENT_FRAG_NODE:
2897 case XML_HTML_DOCUMENT_NODE:
2898#ifdef LIBXML_SGML_ENABLED
2899 case XML_SGML_DOCUMENT_NODE:
2900#endif
2901 return(NULL);
2902 case XML_NAMESPACE_DECL:
2903 /*
2904 * TODO !!! may require extending struct _xmlNs with
2905 * parent field
2906 * C.f. Infoset case...
2907 */
2908 return(NULL);
2909 }
2910 return(NULL);
2911}
2912
2913/**
2914 * xmlXPathNextAncestorOrSelf:
2915 * @ctxt: the XPath Parser context
2916 * @cur: the current node in the traversal
2917 *
2918 * Traversal function for the "ancestor-or-self" direction
2919 * he ancestor-or-self axis contains the context node and ancestors of
2920 * the context node in reverse document order; thus the context node is
2921 * the first node on the axis, and the context node's parent the second;
2922 * parent here is defined the same as with the parent axis.
2923 *
2924 * Returns the next element following that axis
2925 */
2926xmlNodePtr
2927xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2928 if (cur == NULL)
2929 return(ctxt->context->node);
2930 return(xmlXPathNextAncestor(ctxt, cur));
2931}
2932
2933/**
2934 * xmlXPathNextFollowingSibling:
2935 * @ctxt: the XPath Parser context
2936 * @cur: the current node in the traversal
2937 *
2938 * Traversal function for the "following-sibling" direction
2939 * The following-sibling axis contains the following siblings of the context
2940 * node in document order.
2941 *
2942 * Returns the next element following that axis
2943 */
2944xmlNodePtr
2945xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2946 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2947 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2948 return(NULL);
2949 if (cur == (xmlNodePtr) ctxt->context->doc)
2950 return(NULL);
2951 if (cur == NULL)
2952 return(ctxt->context->node->next);
2953 return(cur->next);
2954}
2955
2956/**
2957 * xmlXPathNextPrecedingSibling:
2958 * @ctxt: the XPath Parser context
2959 * @cur: the current node in the traversal
2960 *
2961 * Traversal function for the "preceding-sibling" direction
2962 * The preceding-sibling axis contains the preceding siblings of the context
2963 * node in reverse document order; the first preceding sibling is first on the
2964 * axis; the sibling preceding that node is the second on the axis and so on.
2965 *
2966 * Returns the next element following that axis
2967 */
2968xmlNodePtr
2969xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2970 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2971 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2972 return(NULL);
2973 if (cur == (xmlNodePtr) ctxt->context->doc)
2974 return(NULL);
2975 if (cur == NULL)
2976 return(ctxt->context->node->prev);
2977 return(cur->prev);
2978}
2979
2980/**
2981 * xmlXPathNextFollowing:
2982 * @ctxt: the XPath Parser context
2983 * @cur: the current node in the traversal
2984 *
2985 * Traversal function for the "following" direction
2986 * The following axis contains all nodes in the same document as the context
2987 * node that are after the context node in document order, excluding any
2988 * descendants and excluding attribute nodes and namespace nodes; the nodes
2989 * are ordered in document order
2990 *
2991 * Returns the next element following that axis
2992 */
2993xmlNodePtr
2994xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2995 if (cur != NULL && cur->children != NULL)
2996 return cur->children ;
2997 if (cur == NULL) cur = ctxt->context->node;
2998 if (cur == NULL) return(NULL) ; /* ERROR */
2999 if (cur->next != NULL) return(cur->next) ;
3000 do {
3001 cur = cur->parent;
3002 if (cur == NULL) return(NULL);
3003 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
3004 if (cur->next != NULL) return(cur->next);
3005 } while (cur != NULL);
3006 return(cur);
3007}
3008
3009/*
3010 * xmlXPathIsAncestor:
3011 * @ancestor: the ancestor node
3012 * @node: the current node
3013 *
3014 * Check that @ancestor is a @node's ancestor
3015 *
3016 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
3017 */
3018static int
3019xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
3020 if ((ancestor == NULL) || (node == NULL)) return(0);
3021 /* nodes need to be in the same document */
3022 if (ancestor->doc != node->doc) return(0);
3023 /* avoid searching if ancestor or node is the root node */
3024 if (ancestor == (xmlNodePtr) node->doc) return(1);
3025 if (node == (xmlNodePtr) ancestor->doc) return(0);
3026 while (node->parent != NULL) {
3027 if (node->parent == ancestor)
3028 return(1);
3029 node = node->parent;
3030 }
3031 return(0);
3032}
3033
3034/**
3035 * xmlXPathNextPreceding:
3036 * @ctxt: the XPath Parser context
3037 * @cur: the current node in the traversal
3038 *
3039 * Traversal function for the "preceding" direction
3040 * the preceding axis contains all nodes in the same document as the context
3041 * node that are before the context node in document order, excluding any
3042 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
3043 * ordered in reverse document order
3044 *
3045 * Returns the next element following that axis
3046 */
3047xmlNodePtr
3048xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3049 if (cur == NULL)
3050 cur = ctxt->context->node ;
3051 do {
3052 if (cur->prev != NULL) {
3053 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
3054 ;
3055 return(cur) ;
3056 }
3057
3058 cur = cur->parent;
3059 if (cur == NULL) return(NULL);
3060 if (cur == ctxt->context->doc->children) return(NULL);
3061 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
3062 return(cur);
3063}
3064
3065/**
3066 * xmlXPathNextNamespace:
3067 * @ctxt: the XPath Parser context
3068 * @cur: the current attribute in the traversal
3069 *
3070 * Traversal function for the "namespace" direction
3071 * the namespace axis contains the namespace nodes of the context node;
3072 * the order of nodes on this axis is implementation-defined; the axis will
3073 * be empty unless the context node is an element
3074 *
3075 * Returns the next element following that axis
3076 */
3077xmlNodePtr
3078xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3079 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3080 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
3081 if (ctxt->context->namespaces != NULL)
3082 xmlFree(ctxt->context->namespaces);
3083 ctxt->context->namespaces =
3084 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
3085 if (ctxt->context->namespaces == NULL) return(NULL);
3086 ctxt->context->nsNr = 0;
3087 }
3088 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
3089}
3090
3091/**
3092 * xmlXPathNextAttribute:
3093 * @ctxt: the XPath Parser context
3094 * @cur: the current attribute in the traversal
3095 *
3096 * Traversal function for the "attribute" direction
3097 * TODO: support DTD inherited default attributes
3098 *
3099 * Returns the next element following that axis
3100 */
3101xmlNodePtr
3102xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3103 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
3104 if (cur == NULL) {
3105 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3106 return(NULL);
3107 return((xmlNodePtr)ctxt->context->node->properties);
3108 }
3109 return((xmlNodePtr)cur->next);
3110}
3111
3112/************************************************************************
3113 * *
3114 * NodeTest Functions *
3115 * *
3116 ************************************************************************/
3117
3118typedef enum {
3119 NODE_TEST_NONE = 0,
3120 NODE_TEST_TYPE = 1,
3121 NODE_TEST_PI = 2,
3122 NODE_TEST_ALL = 3,
3123 NODE_TEST_NS = 4,
3124 NODE_TEST_NAME = 5
3125} xmlXPathTestVal;
3126
3127typedef enum {
3128 NODE_TYPE_NODE = 0,
3129 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
3130 NODE_TYPE_TEXT = XML_TEXT_NODE,
3131 NODE_TYPE_PI = XML_PI_NODE
3132} xmlXPathTypeVal;
3133
3134#define IS_FUNCTION 200
3135
3136/**
3137 * xmlXPathNodeCollectAndTest:
3138 * @ctxt: the XPath Parser context
3139 * @axis: the XPath axis
3140 * @test: the XPath test
3141 * @type: the XPath type
3142 * @prefix: the namesapce prefix if any
3143 * @name: the name used in the search if any
3144 *
3145 * This is the function implementing a step: based on the current list
3146 * of nodes, it builds up a new list, looking at all nodes under that
3147 * axis and selecting them.
3148 *
3149 * Returns the new NodeSet resulting from the search.
3150 */
3151void
3152xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
3153 xmlXPathTestVal test, xmlXPathTypeVal type,
3154 const xmlChar *prefix, const xmlChar *name) {
3155#ifdef DEBUG_STEP
3156 int n = 0, t = 0;
3157#endif
3158 int i;
3159 xmlNodeSetPtr ret;
3160 xmlXPathTraversalFunction next = NULL;
3161 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
3162 xmlNodePtr cur = NULL;
3163 xmlXPathObjectPtr obj;
3164 xmlNodeSetPtr nodelist;
3165
3166 CHECK_TYPE(XPATH_NODESET);
3167 obj = valuePop(ctxt);
3168 addNode = xmlXPathNodeSetAdd;
3169
3170#ifdef DEBUG_STEP
3171 xmlGenericError(xmlGenericErrorContext,
3172 "new step : ");
3173#endif
3174 switch (axis) {
3175 case AXIS_ANCESTOR:
3176#ifdef DEBUG_STEP
3177 xmlGenericError(xmlGenericErrorContext,
3178 "axis 'ancestors' ");
3179#endif
3180 next = xmlXPathNextAncestor; break;
3181 case AXIS_ANCESTOR_OR_SELF:
3182#ifdef DEBUG_STEP
3183 xmlGenericError(xmlGenericErrorContext,
3184 "axis 'ancestors-or-self' ");
3185#endif
3186 next = xmlXPathNextAncestorOrSelf; break;
3187 case AXIS_ATTRIBUTE:
3188#ifdef DEBUG_STEP
3189 xmlGenericError(xmlGenericErrorContext,
3190 "axis 'attributes' ");
3191#endif
3192 next = xmlXPathNextAttribute; break;
3193 break;
3194 case AXIS_CHILD:
3195#ifdef DEBUG_STEP
3196 xmlGenericError(xmlGenericErrorContext,
3197 "axis 'child' ");
3198#endif
3199 next = xmlXPathNextChild; break;
3200 case AXIS_DESCENDANT:
3201#ifdef DEBUG_STEP
3202 xmlGenericError(xmlGenericErrorContext,
3203 "axis 'descendant' ");
3204#endif
3205 next = xmlXPathNextDescendant; break;
3206 case AXIS_DESCENDANT_OR_SELF:
3207#ifdef DEBUG_STEP
3208 xmlGenericError(xmlGenericErrorContext,
3209 "axis 'descendant-or-self' ");
3210#endif
3211 next = xmlXPathNextDescendantOrSelf; break;
3212 case AXIS_FOLLOWING:
3213#ifdef DEBUG_STEP
3214 xmlGenericError(xmlGenericErrorContext,
3215 "axis 'following' ");
3216#endif
3217 next = xmlXPathNextFollowing; break;
3218 case AXIS_FOLLOWING_SIBLING:
3219#ifdef DEBUG_STEP
3220 xmlGenericError(xmlGenericErrorContext,
3221 "axis 'following-siblings' ");
3222#endif
3223 next = xmlXPathNextFollowingSibling; break;
3224 case AXIS_NAMESPACE:
3225#ifdef DEBUG_STEP
3226 xmlGenericError(xmlGenericErrorContext,
3227 "axis 'namespace' ");
3228#endif
3229 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
3230 break;
3231 case AXIS_PARENT:
3232#ifdef DEBUG_STEP
3233 xmlGenericError(xmlGenericErrorContext,
3234 "axis 'parent' ");
3235#endif
3236 next = xmlXPathNextParent; break;
3237 case AXIS_PRECEDING:
3238#ifdef DEBUG_STEP
3239 xmlGenericError(xmlGenericErrorContext,
3240 "axis 'preceding' ");
3241#endif
3242 next = xmlXPathNextPreceding; break;
3243 case AXIS_PRECEDING_SIBLING:
3244#ifdef DEBUG_STEP
3245 xmlGenericError(xmlGenericErrorContext,
3246 "axis 'preceding-sibling' ");
3247#endif
3248 next = xmlXPathNextPrecedingSibling; break;
3249 case AXIS_SELF:
3250#ifdef DEBUG_STEP
3251 xmlGenericError(xmlGenericErrorContext,
3252 "axis 'self' ");
3253#endif
3254 next = xmlXPathNextSelf; break;
3255 }
3256 if (next == NULL)
3257 return;
3258
3259 nodelist = obj->nodesetval;
3260 if ((nodelist != NULL) &&
3261 (nodelist->nodeNr <= 1))
3262 addNode = xmlXPathNodeSetAddUnique;
3263 else
3264 addNode = xmlXPathNodeSetAdd;
3265 ret = xmlXPathNodeSetCreate(NULL);
3266#ifdef DEBUG_STEP
3267 xmlGenericError(xmlGenericErrorContext,
3268 " context contains %d nodes\n",
3269 nodelist->nodeNr);
3270 switch (test) {
3271 case NODE_TEST_NODE:
3272 xmlGenericError(xmlGenericErrorContext,
3273 " searching all nodes\n");
3274 break;
3275 case NODE_TEST_NONE:
3276 xmlGenericError(xmlGenericErrorContext,
3277 " searching for none !!!\n");
3278 break;
3279 case NODE_TEST_TYPE:
3280 xmlGenericError(xmlGenericErrorContext,
3281 " searching for type %d\n", type);
3282 break;
3283 case NODE_TEST_PI:
3284 xmlGenericError(xmlGenericErrorContext,
3285 " searching for PI !!!\n");
3286 break;
3287 case NODE_TEST_ALL:
3288 xmlGenericError(xmlGenericErrorContext,
3289 " searching for *\n");
3290 break;
3291 case NODE_TEST_NS:
3292 xmlGenericError(xmlGenericErrorContext,
3293 " searching for namespace %s\n",
3294 prefix);
3295 break;
3296 case NODE_TEST_NAME:
3297 xmlGenericError(xmlGenericErrorContext,
3298 " searching for name %s\n", name);
3299 if (prefix != NULL)
3300 xmlGenericError(xmlGenericErrorContext,
3301 " with namespace %s\n",
3302 prefix);
3303 break;
3304 }
3305 xmlGenericError(xmlGenericErrorContext, "Testing : ");
3306#endif
3307 /*
3308 * 2.3 Node Tests
3309 * - For the attribute axis, the principal node type is attribute.
3310 * - For the namespace axis, the principal node type is namespace.
3311 * - For other axes, the principal node type is element.
3312 *
3313 * A node test * is true for any node of the
3314 * principal node type. For example, child::* willi
3315 * select all element children of the context node
3316 */
3317 for (i = 0;i < nodelist->nodeNr; i++) {
3318 ctxt->context->node = nodelist->nodeTab[i];
3319
3320 cur = NULL;
3321 do {
3322 cur = next(ctxt, cur);
3323 if (cur == NULL) break;
3324#ifdef DEBUG_STEP
3325 t++;
3326 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
3327#endif
3328 switch (test) {
3329 case NODE_TEST_NONE:
3330 STRANGE
3331 return;
3332 case NODE_TEST_TYPE:
3333 if ((cur->type == type) ||
3334 ((type == NODE_TYPE_NODE) &&
3335 ((cur->type == XML_DOCUMENT_NODE) ||
3336 (cur->type == XML_HTML_DOCUMENT_NODE) ||
3337 (cur->type == XML_ELEMENT_NODE) ||
3338 (cur->type == XML_PI_NODE) ||
3339 (cur->type == XML_COMMENT_NODE) ||
3340 (cur->type == XML_CDATA_SECTION_NODE) ||
3341 (cur->type == XML_TEXT_NODE)))) {
3342#ifdef DEBUG_STEP
3343 n++;
3344#endif
3345 addNode(ret, cur);
3346 }
3347 break;
3348 case NODE_TEST_PI:
3349 if (cur->type == XML_PI_NODE) {
3350 if ((name != NULL) &&
3351 (!xmlStrEqual(name, cur->name)))
3352 break;
3353#ifdef DEBUG_STEP
3354 n++;
3355#endif
3356 addNode(ret, cur);
3357 }
3358 break;
3359 case NODE_TEST_ALL:
3360 if (axis == AXIS_ATTRIBUTE) {
3361 if (cur->type == XML_ATTRIBUTE_NODE) {
3362#ifdef DEBUG_STEP
3363 n++;
3364#endif
3365 addNode(ret, cur);
3366 }
3367 } else if (axis == AXIS_NAMESPACE) {
3368 if (cur->type == XML_NAMESPACE_DECL) {
3369#ifdef DEBUG_STEP
3370 n++;
3371#endif
3372 addNode(ret, cur);
3373 }
3374 } else {
3375 if ((cur->type == XML_ELEMENT_NODE) ||
3376 (cur->type == XML_DOCUMENT_NODE) ||
3377 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3378 if (prefix == NULL) {
3379#ifdef DEBUG_STEP
3380 n++;
3381#endif
3382 addNode(ret, cur);
3383 } else if ((cur->ns != NULL) &&
3384 (xmlStrEqual(prefix,
3385 cur->ns->href))) {
3386#ifdef DEBUG_STEP
3387 n++;
3388#endif
3389 addNode(ret, cur);
3390 }
3391 }
3392 }
3393 break;
3394 case NODE_TEST_NS: {
3395 TODO;
3396 break;
3397 }
3398 case NODE_TEST_NAME:
3399 switch (cur->type) {
3400 case XML_ELEMENT_NODE:
3401 if (xmlStrEqual(name, cur->name)) {
3402 if (prefix == NULL) {
3403 if ((cur->ns == NULL) ||
3404 (cur->ns->prefix == NULL)) {
3405#ifdef DEBUG_STEP
3406 n++;
3407#endif
3408 addNode(ret, cur);
3409 }
3410 } else {
3411 if ((cur->ns != NULL) &&
3412 (xmlStrEqual(prefix,
3413 cur->ns->href))) {
3414#ifdef DEBUG_STEP
3415 n++;
3416#endif
3417 addNode(ret, cur);
3418 }
3419 }
3420 }
3421 break;
3422 case XML_ATTRIBUTE_NODE: {
3423 xmlAttrPtr attr = (xmlAttrPtr) cur;
3424 if (xmlStrEqual(name, attr->name)) {
3425 if (prefix == NULL) {
3426 if ((attr->ns == NULL) ||
3427 (attr->ns->prefix == NULL)) {
3428#ifdef DEBUG_STEP
3429 n++;
3430#endif
3431 addNode(ret, (xmlNodePtr) attr);
3432 }
3433 } else {
3434 if ((attr->ns != NULL) &&
3435 (xmlStrEqual(prefix,
3436 attr->ns->href))) {
3437#ifdef DEBUG_STEP
3438 n++;
3439#endif
3440 addNode(ret, (xmlNodePtr) attr);
3441 }
3442 }
3443 }
3444 break;
3445 }
3446 case XML_NAMESPACE_DECL: {
3447 TODO;
3448 break;
3449 }
3450 default:
3451 break;
3452 }
3453 break;
3454 }
3455 } while (cur != NULL);
3456 }
3457#ifdef DEBUG_STEP
3458 xmlGenericError(xmlGenericErrorContext,
3459 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
3460#endif
3461 xmlXPathFreeObject(obj);
3462 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
3463}
3464
3465
3466/************************************************************************
3467 * *
3468 * Implicit tree core function library *
3469 * *
3470 ************************************************************************/
3471
3472/**
3473 * xmlXPathRoot:
3474 * @ctxt: the XPath Parser context
3475 *
3476 * Initialize the context to the root of the document
3477 */
3478void
3479xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
3480 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
3481 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3482}
3483
3484/************************************************************************
3485 * *
3486 * The explicit core function library *
3487 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3488 * *
3489 ************************************************************************/
3490
3491
3492/**
3493 * xmlXPathLastFunction:
3494 * @ctxt: the XPath Parser context
3495 * @nargs: the number of arguments
3496 *
3497 * Implement the last() XPath function
3498 * number last()
3499 * The last function returns the number of nodes in the context node list.
3500 */
3501void
3502xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3503 CHECK_ARITY(0);
3504 if (ctxt->context->contextSize >= 0) {
3505 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3506#ifdef DEBUG_EXPR
3507 xmlGenericError(xmlGenericErrorContext,
3508 "last() : %d\n", ctxt->context->contextSize);
3509#endif
3510 } else {
3511 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
3512 }
3513}
3514
3515/**
3516 * xmlXPathPositionFunction:
3517 * @ctxt: the XPath Parser context
3518 * @nargs: the number of arguments
3519 *
3520 * Implement the position() XPath function
3521 * number position()
3522 * The position function returns the position of the context node in the
3523 * context node list. The first position is 1, and so the last positionr
3524 * will be equal to last().
3525 */
3526void
3527xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3528 CHECK_ARITY(0);
3529 if (ctxt->context->proximityPosition >= 0) {
3530 valuePush(ctxt,
3531 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
3532#ifdef DEBUG_EXPR
3533 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
3534 ctxt->context->proximityPosition);
3535#endif
3536 } else {
3537 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
3538 }
3539}
3540
3541/**
3542 * xmlXPathCountFunction:
3543 * @ctxt: the XPath Parser context
3544 * @nargs: the number of arguments
3545 *
3546 * Implement the count() XPath function
3547 * number count(node-set)
3548 */
3549void
3550xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3551 xmlXPathObjectPtr cur;
3552
3553 CHECK_ARITY(1);
3554 if ((ctxt->value == NULL) ||
3555 ((ctxt->value->type != XPATH_NODESET) &&
3556 (ctxt->value->type != XPATH_XSLT_TREE)))
3557 XP_ERROR(XPATH_INVALID_TYPE);
3558 cur = valuePop(ctxt);
3559
3560 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
3561 xmlXPathFreeObject(cur);
3562}
3563
3564/**
3565 * xmlXPathIdFunction:
3566 * @ctxt: the XPath Parser context
3567 * @nargs: the number of arguments
3568 *
3569 * Implement the id() XPath function
3570 * node-set id(object)
3571 * The id function selects elements by their unique ID
3572 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3573 * then the result is the union of the result of applying id to the
3574 * string value of each of the nodes in the argument node-set. When the
3575 * argument to id is of any other type, the argument is converted to a
3576 * string as if by a call to the string function; the string is split
3577 * into a whitespace-separated list of tokens (whitespace is any sequence
3578 * of characters matching the production S); the result is a node-set
3579 * containing the elements in the same document as the context node that
3580 * have a unique ID equal to any of the tokens in the list.
3581 */
3582void
3583xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3584 const xmlChar *tokens;
3585 const xmlChar *cur;
3586 xmlChar *ID;
3587 xmlAttrPtr attr;
3588 xmlNodePtr elem = NULL;
3589 xmlXPathObjectPtr ret, obj;
3590
3591 CHECK_ARITY(1);
3592 obj = valuePop(ctxt);
3593 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3594 if (obj->type == XPATH_NODESET) {
3595 xmlXPathObjectPtr newobj;
3596 int i;
3597
3598 ret = xmlXPathNewNodeSet(NULL);
3599
3600 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3601 valuePush(ctxt,
3602 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3603 xmlXPathStringFunction(ctxt, 1);
3604 xmlXPathIdFunction(ctxt, 1);
3605 newobj = valuePop(ctxt);
3606 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3607 newobj->nodesetval);
3608 xmlXPathFreeObject(newobj);
3609 }
3610
3611 xmlXPathFreeObject(obj);
3612 valuePush(ctxt, ret);
3613 return;
3614 }
3615 if (obj->type != XPATH_STRING) {
3616 valuePush(ctxt, obj);
3617 xmlXPathStringFunction(ctxt, 1);
3618 obj = valuePop(ctxt);
3619 if (obj->type != XPATH_STRING) {
3620 xmlXPathFreeObject(obj);
3621 return;
3622 }
3623 }
3624 tokens = obj->stringval;
3625
3626 ret = xmlXPathNewNodeSet(NULL);
3627 valuePush(ctxt, ret);
3628 if (tokens == NULL) {
3629 xmlXPathFreeObject(obj);
3630 return;
3631 }
3632
3633 cur = tokens;
3634
3635 while (IS_BLANK(*cur)) cur++;
3636 while (*cur != 0) {
3637 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3638 (*cur == '.') || (*cur == '-') ||
3639 (*cur == '_') || (*cur == ':') ||
3640 (IS_COMBINING(*cur)) ||
3641 (IS_EXTENDER(*cur)))
3642 cur++;
3643
3644 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3645
3646 ID = xmlStrndup(tokens, cur - tokens);
3647 attr = xmlGetID(ctxt->context->doc, ID);
3648 if (attr != NULL) {
3649 elem = attr->parent;
3650 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3651 }
3652 if (ID != NULL)
3653 xmlFree(ID);
3654
3655 while (IS_BLANK(*cur)) cur++;
3656 tokens = cur;
3657 }
3658 xmlXPathFreeObject(obj);
3659 return;
3660}
3661
3662/**
3663 * xmlXPathLocalNameFunction:
3664 * @ctxt: the XPath Parser context
3665 * @nargs: the number of arguments
3666 *
3667 * Implement the local-name() XPath function
3668 * string local-name(node-set?)
3669 * The local-name function returns a string containing the local part
3670 * of the name of the node in the argument node-set that is first in
3671 * document order. If the node-set is empty or the first node has no
3672 * name, an empty string is returned. If the argument is omitted it
3673 * defaults to the context node.
3674 */
3675void
3676xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3677 xmlXPathObjectPtr cur;
3678
3679 if (nargs == 0) {
3680 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3681 nargs = 1;
3682 }
3683
3684 CHECK_ARITY(1);
3685 if ((ctxt->value == NULL) ||
3686 ((ctxt->value->type != XPATH_NODESET) &&
3687 (ctxt->value->type != XPATH_XSLT_TREE)))
3688 XP_ERROR(XPATH_INVALID_TYPE);
3689 cur = valuePop(ctxt);
3690
3691 if (cur->nodesetval->nodeNr == 0) {
3692 valuePush(ctxt, xmlXPathNewCString(""));
3693 } else {
3694 int i = 0; /* Should be first in document order !!!!! */
3695 switch (cur->nodesetval->nodeTab[i]->type) {
3696 case XML_ELEMENT_NODE:
3697 case XML_ATTRIBUTE_NODE:
3698 case XML_PI_NODE:
3699 valuePush(ctxt,
3700 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
3701 break;
3702 case XML_NAMESPACE_DECL:
3703 valuePush(ctxt, xmlXPathNewString(
3704 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
3705 break;
3706 default:
3707 valuePush(ctxt, xmlXPathNewCString(""));
3708 }
3709 }
3710 xmlXPathFreeObject(cur);
3711}
3712
3713/**
3714 * xmlXPathNamespaceURIFunction:
3715 * @ctxt: the XPath Parser context
3716 * @nargs: the number of arguments
3717 *
3718 * Implement the namespace-uri() XPath function
3719 * string namespace-uri(node-set?)
3720 * The namespace-uri function returns a string containing the
3721 * namespace URI of the expanded name of the node in the argument
3722 * node-set that is first in document order. If the node-set is empty,
3723 * the first node has no name, or the expanded name has no namespace
3724 * URI, an empty string is returned. If the argument is omitted it
3725 * defaults to the context node.
3726 */
3727void
3728xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3729 xmlXPathObjectPtr cur;
3730
3731 if (nargs == 0) {
3732 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3733 nargs = 1;
3734 }
3735 CHECK_ARITY(1);
3736 if ((ctxt->value == NULL) ||
3737 ((ctxt->value->type != XPATH_NODESET) &&
3738 (ctxt->value->type != XPATH_XSLT_TREE)))
3739 XP_ERROR(XPATH_INVALID_TYPE);
3740 cur = valuePop(ctxt);
3741
3742 if (cur->nodesetval->nodeNr == 0) {
3743 valuePush(ctxt, xmlXPathNewCString(""));
3744 } else {
3745 int i = 0; /* Should be first in document order !!!!! */
3746 switch (cur->nodesetval->nodeTab[i]->type) {
3747 case XML_ELEMENT_NODE:
3748 case XML_ATTRIBUTE_NODE:
3749 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3750 valuePush(ctxt, xmlXPathNewCString(""));
3751 else
3752 valuePush(ctxt, xmlXPathNewString(
3753 cur->nodesetval->nodeTab[i]->ns->href));
3754 break;
3755 default:
3756 valuePush(ctxt, xmlXPathNewCString(""));
3757 }
3758 }
3759 xmlXPathFreeObject(cur);
3760}
3761
3762/**
3763 * xmlXPathNameFunction:
3764 * @ctxt: the XPath Parser context
3765 * @nargs: the number of arguments
3766 *
3767 * Implement the name() XPath function
3768 * string name(node-set?)
3769 * The name function returns a string containing a QName representing
3770 * the name of the node in the argument node-set that is first in documenti
3771 * order. The QName must represent the name with respect to the namespace
3772 * declarations in effect on the node whose name is being represented.
3773 * Typically, this will be the form in which the name occurred in the XML
3774 * source. This need not be the case if there are namespace declarations
3775 * in effect on the node that associate multiple prefixes with the same
3776 * namespace. However, an implementation may include information about
3777 * the original prefix in its representation of nodes; in this case, an
3778 * implementation can ensure that the returned string is always the same
3779 * as the QName used in the XML source. If the argument it omitted it
3780 * defaults to the context node.
3781 * Libxml keep the original prefix so the "real qualified name" used is
3782 * returned.
3783 */
3784void
3785xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3786 xmlXPathObjectPtr cur;
3787
3788 if (nargs == 0) {
3789 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3790 nargs = 1;
3791 }
3792
3793 CHECK_ARITY(1);
3794 if ((ctxt->value == NULL) ||
3795 ((ctxt->value->type != XPATH_NODESET) &&
3796 (ctxt->value->type != XPATH_XSLT_TREE)))
3797 XP_ERROR(XPATH_INVALID_TYPE);
3798 cur = valuePop(ctxt);
3799
3800 if (cur->nodesetval->nodeNr == 0) {
3801 valuePush(ctxt, xmlXPathNewCString(""));
3802 } else {
3803 int i = 0; /* Should be first in document order !!!!! */
3804
3805 switch (cur->nodesetval->nodeTab[i]->type) {
3806 case XML_ELEMENT_NODE:
3807 case XML_ATTRIBUTE_NODE:
3808 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3809 valuePush(ctxt, xmlXPathNewString(
3810 cur->nodesetval->nodeTab[i]->name));
3811
3812 else {
3813 char name[2000];
3814#ifdef HAVE_SNPRINTF
3815 snprintf(name, sizeof(name), "%s:%s",
3816 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3817 (char *) cur->nodesetval->nodeTab[i]->name);
3818#else
3819 sprintf(name, "%s:%s",
3820 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3821 (char *) cur->nodesetval->nodeTab[i]->name);
3822#endif
3823 name[sizeof(name) - 1] = 0;
3824 valuePush(ctxt, xmlXPathNewCString(name));
3825 }
3826 break;
3827 default:
3828 valuePush(ctxt,
3829 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3830 xmlXPathLocalNameFunction(ctxt, 1);
3831 }
3832 }
3833 xmlXPathFreeObject(cur);
3834}
3835
3836/**
3837 * xmlXPathStringFunction:
3838 * @ctxt: the XPath Parser context
3839 * @nargs: the number of arguments
3840 *
3841 * Implement the string() XPath function
3842 * string string(object?)
3843 * he string function converts an object to a string as follows:
3844 * - A node-set is converted to a string by returning the value of
3845 * the node in the node-set that is first in document order.
3846 * If the node-set is empty, an empty string is returned.
3847 * - A number is converted to a string as follows
3848 * + NaN is converted to the string NaN
3849 * + positive zero is converted to the string 0
3850 * + negative zero is converted to the string 0
3851 * + positive infinity is converted to the string Infinity
3852 * + negative infinity is converted to the string -Infinity
3853 * + if the number is an integer, the number is represented in
3854 * decimal form as a Number with no decimal point and no leading
3855 * zeros, preceded by a minus sign (-) if the number is negative
3856 * + otherwise, the number is represented in decimal form as a
3857 * Number including a decimal point with at least one digit
3858 * before the decimal point and at least one digit after the
3859 * decimal point, preceded by a minus sign (-) if the number
3860 * is negative; there must be no leading zeros before the decimal
3861 * point apart possibly from the one required digit immediatelyi
3862 * before the decimal point; beyond the one required digit
3863 * after the decimal point there must be as many, but only as
3864 * many, more digits as are needed to uniquely distinguish the
3865 * number from all other IEEE 754 numeric values.
3866 * - The boolean false value is converted to the string false.
3867 * The boolean true value is converted to the string true.
3868 *
3869 * If the argument is omitted, it defaults to a node-set with the
3870 * context node as its only member.
3871 */
3872void
3873xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3874 xmlXPathObjectPtr cur;
3875
3876 if (nargs == 0) {
3877 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3878 nargs = 1;
3879 }
3880
3881 CHECK_ARITY(1);
3882 cur = valuePop(ctxt);
3883 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3884 switch (cur->type) {
3885 case XPATH_UNDEFINED:
3886#ifdef DEBUG_EXPR
3887 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3888#endif
3889 valuePush(ctxt, xmlXPathNewCString(""));
3890 break;
3891 case XPATH_XSLT_TREE:
3892 case XPATH_NODESET:
3893 if (cur->nodesetval == NULL)
3894 valuePush(ctxt, xmlXPathNewCString(""));
3895 else if (cur->nodesetval->nodeNr == 0) {
3896 valuePush(ctxt, xmlXPathNewCString(""));
3897 } else {
3898 xmlChar *res;
3899 int i = 0; /* Should be first in document order !!!!! */
3900 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
3901 valuePush(ctxt, xmlXPathNewString(res));
3902 if (res != NULL)
3903 xmlFree(res);
3904 }
3905 xmlXPathFreeObject(cur);
3906 return;
3907 case XPATH_STRING:
3908 valuePush(ctxt, cur);
3909 return;
3910 case XPATH_BOOLEAN:
3911 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
3912 else valuePush(ctxt, xmlXPathNewCString("false"));
3913 xmlXPathFreeObject(cur);
3914 return;
3915 case XPATH_NUMBER: {
3916 char buf[100];
3917
3918 if (isnan(cur->floatval))
3919 sprintf(buf, "NaN");
3920 else if (isinf(cur->floatval) > 0)
3921 sprintf(buf, "+Infinity");
3922 else if (isinf(cur->floatval) < 0)
3923 sprintf(buf, "-Infinity");
3924 else
3925 sprintf(buf, "%0g", cur->floatval);
3926 valuePush(ctxt, xmlXPathNewCString(buf));
3927 xmlXPathFreeObject(cur);
3928 return;
3929 }
3930 case XPATH_USERS:
3931 case XPATH_POINT:
3932 case XPATH_RANGE:
3933 case XPATH_LOCATIONSET:
3934 TODO
3935 valuePush(ctxt, xmlXPathNewCString(""));
3936 break;
3937 }
3938 STRANGE
3939}
3940
3941/**
3942 * xmlXPathStringLengthFunction:
3943 * @ctxt: the XPath Parser context
3944 * @nargs: the number of arguments
3945 *
3946 * Implement the string-length() XPath function
3947 * number string-length(string?)
3948 * The string-length returns the number of characters in the string
3949 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3950 * the context node converted to a string, in other words the value
3951 * of the context node.
3952 */
3953void
3954xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3955 xmlXPathObjectPtr cur;
3956
3957 if (nargs == 0) {
3958 if (ctxt->context->node == NULL) {
3959 valuePush(ctxt, xmlXPathNewFloat(0));
3960 } else {
3961 xmlChar *content;
3962
3963 content = xmlNodeGetContent(ctxt->context->node);
3964 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
3965 xmlFree(content);
3966 }
3967 return;
3968 }
3969 CHECK_ARITY(1);
3970 CAST_TO_STRING;
3971 CHECK_TYPE(XPATH_STRING);
3972 cur = valuePop(ctxt);
3973 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3974 xmlXPathFreeObject(cur);
3975}
3976
3977/**
3978 * xmlXPathConcatFunction:
3979 * @ctxt: the XPath Parser context
3980 * @nargs: the number of arguments
3981 *
3982 * Implement the concat() XPath function
3983 * string concat(string, string, string*)
3984 * The concat function returns the concatenation of its arguments.
3985 */
3986void
3987xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3988 xmlXPathObjectPtr cur, newobj;
3989 xmlChar *tmp;
3990
3991 if (nargs < 2) {
3992 CHECK_ARITY(2);
3993 }
3994
3995 CAST_TO_STRING;
3996 cur = valuePop(ctxt);
3997 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3998 xmlXPathFreeObject(cur);
3999 return;
4000 }
4001 nargs--;
4002
4003 while (nargs > 0) {
4004 CAST_TO_STRING;
4005 newobj = valuePop(ctxt);
4006 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4007 xmlXPathFreeObject(newobj);
4008 xmlXPathFreeObject(cur);
4009 XP_ERROR(XPATH_INVALID_TYPE);
4010 }
4011 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4012 newobj->stringval = cur->stringval;
4013 cur->stringval = tmp;
4014
4015 xmlXPathFreeObject(newobj);
4016 nargs--;
4017 }
4018 valuePush(ctxt, cur);
4019}
4020
4021/**
4022 * xmlXPathContainsFunction:
4023 * @ctxt: the XPath Parser context
4024 * @nargs: the number of arguments
4025 *
4026 * Implement the contains() XPath function
4027 * boolean contains(string, string)
4028 * The contains function returns true if the first argument string
4029 * contains the second argument string, and otherwise returns false.
4030 */
4031void
4032xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4033 xmlXPathObjectPtr hay, needle;
4034
4035 CHECK_ARITY(2);
4036 CAST_TO_STRING;
4037 CHECK_TYPE(XPATH_STRING);
4038 needle = valuePop(ctxt);
4039 CAST_TO_STRING;
4040 hay = valuePop(ctxt);
4041 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4042 xmlXPathFreeObject(hay);
4043 xmlXPathFreeObject(needle);
4044 XP_ERROR(XPATH_INVALID_TYPE);
4045 }
4046 if (xmlStrstr(hay->stringval, needle->stringval))
4047 valuePush(ctxt, xmlXPathNewBoolean(1));
4048 else
4049 valuePush(ctxt, xmlXPathNewBoolean(0));
4050 xmlXPathFreeObject(hay);
4051 xmlXPathFreeObject(needle);
4052}
4053
4054/**
4055 * xmlXPathStartsWithFunction:
4056 * @ctxt: the XPath Parser context
4057 * @nargs: the number of arguments
4058 *
4059 * Implement the starts-with() XPath function
4060 * boolean starts-with(string, string)
4061 * The starts-with function returns true if the first argument string
4062 * starts with the second argument string, and otherwise returns false.
4063 */
4064void
4065xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4066 xmlXPathObjectPtr hay, needle;
4067 int n;
4068
4069 CHECK_ARITY(2);
4070 CAST_TO_STRING;
4071 CHECK_TYPE(XPATH_STRING);
4072 needle = valuePop(ctxt);
4073 CAST_TO_STRING;
4074 hay = valuePop(ctxt);
4075 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4076 xmlXPathFreeObject(hay);
4077 xmlXPathFreeObject(needle);
4078 XP_ERROR(XPATH_INVALID_TYPE);
4079 }
4080 n = xmlStrlen(needle->stringval);
4081 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4082 valuePush(ctxt, xmlXPathNewBoolean(0));
4083 else
4084 valuePush(ctxt, xmlXPathNewBoolean(1));
4085 xmlXPathFreeObject(hay);
4086 xmlXPathFreeObject(needle);
4087}
4088
4089/**
4090 * xmlXPathSubstringFunction:
4091 * @ctxt: the XPath Parser context
4092 * @nargs: the number of arguments
4093 *
4094 * Implement the substring() XPath function
4095 * string substring(string, number, number?)
4096 * The substring function returns the substring of the first argument
4097 * starting at the position specified in the second argument with
4098 * length specified in the third argument. For example,
4099 * substring("12345",2,3) returns "234". If the third argument is not
4100 * specified, it returns the substring starting at the position specified
4101 * in the second argument and continuing to the end of the string. For
4102 * example, substring("12345",2) returns "2345". More precisely, each
4103 * character in the string (see [3.6 Strings]) is considered to have a
4104 * numeric position: the position of the first character is 1, the position
4105 * of the second character is 2 and so on. The returned substring contains
4106 * those characters for which the position of the character is greater than
4107 * or equal to the second argument and, if the third argument is specified,
4108 * less than the sum of the second and third arguments; the comparisons
4109 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4110 * - substring("12345", 1.5, 2.6) returns "234"
4111 * - substring("12345", 0, 3) returns "12"
4112 * - substring("12345", 0 div 0, 3) returns ""
4113 * - substring("12345", 1, 0 div 0) returns ""
4114 * - substring("12345", -42, 1 div 0) returns "12345"
4115 * - substring("12345", -1 div 0, 1 div 0) returns ""
4116 */
4117void
4118xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4119 xmlXPathObjectPtr str, start, len;
4120 double le, in;
4121 int i, l;
4122 xmlChar *ret;
4123
4124 /*
4125 * Conformance needs to be checked !!!!!
4126 */
4127 if (nargs < 2) {
4128 CHECK_ARITY(2);
4129 }
4130 if (nargs > 3) {
4131 CHECK_ARITY(3);
4132 }
4133 if (nargs == 3) {
4134 CAST_TO_NUMBER;
4135 CHECK_TYPE(XPATH_NUMBER);
4136 len = valuePop(ctxt);
4137 le = len->floatval;
4138 xmlXPathFreeObject(len);
4139 } else {
4140 le = 2000000000;
4141 }
4142 CAST_TO_NUMBER;
4143 CHECK_TYPE(XPATH_NUMBER);
4144 start = valuePop(ctxt);
4145 in = start->floatval;
4146 xmlXPathFreeObject(start);
4147 CAST_TO_STRING;
4148 CHECK_TYPE(XPATH_STRING);
4149 str = valuePop(ctxt);
4150 le += in;
4151
4152 /* integer index of the first char */
4153 i = (int) in;
4154 if (((double)i) != in) i++;
4155
4156 /* integer index of the last char */
4157 l = (int) le;
4158 if (((double)l) != le) l++;
4159
4160 /* back to a zero based len */
4161 i--;
4162 l--;
4163
4164 /* check against the string len */
4165 if (l > 1024) {
4166 l = xmlStrlen(str->stringval);
4167 }
4168 if (i < 0) {
4169 i = 0;
4170 }
4171
4172 /* number of chars to copy */
4173 l -= i;
4174
4175 ret = xmlStrsub(str->stringval, i, l);
4176 if (ret == NULL)
4177 valuePush(ctxt, xmlXPathNewCString(""));
4178 else {
4179 valuePush(ctxt, xmlXPathNewString(ret));
4180 xmlFree(ret);
4181 }
4182 xmlXPathFreeObject(str);
4183}
4184
4185/**
4186 * xmlXPathSubstringBeforeFunction:
4187 * @ctxt: the XPath Parser context
4188 * @nargs: the number of arguments
4189 *
4190 * Implement the substring-before() XPath function
4191 * string substring-before(string, string)
4192 * The substring-before function returns the substring of the first
4193 * argument string that precedes the first occurrence of the second
4194 * argument string in the first argument string, or the empty string
4195 * if the first argument string does not contain the second argument
4196 * string. For example, substring-before("1999/04/01","/") returns 1999.
4197 */
4198void
4199xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4200 xmlXPathObjectPtr str;
4201 xmlXPathObjectPtr find;
4202 xmlBufferPtr target;
4203 const xmlChar *point;
4204 int offset;
4205
4206 CHECK_ARITY(2);
4207 CAST_TO_STRING;
4208 find = valuePop(ctxt);
4209 CAST_TO_STRING;
4210 str = valuePop(ctxt);
4211
4212 target = xmlBufferCreate();
4213 if (target) {
4214 point = xmlStrstr(str->stringval, find->stringval);
4215 if (point) {
4216 offset = (int)(point - str->stringval);
4217 xmlBufferAdd(target, str->stringval, offset);
4218 }
4219 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4220 xmlBufferFree(target);
4221 }
4222
4223 xmlXPathFreeObject(str);
4224 xmlXPathFreeObject(find);
4225}
4226
4227/**
4228 * xmlXPathSubstringAfterFunction:
4229 * @ctxt: the XPath Parser context
4230 * @nargs: the number of arguments
4231 *
4232 * Implement the substring-after() XPath function
4233 * string substring-after(string, string)
4234 * The substring-after function returns the substring of the first
4235 * argument string that follows the first occurrence of the second
4236 * argument string in the first argument string, or the empty stringi
4237 * if the first argument string does not contain the second argument
4238 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4239 * and substring-after("1999/04/01","19") returns 99/04/01.
4240 */
4241void
4242xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4243 xmlXPathObjectPtr str;
4244 xmlXPathObjectPtr find;
4245 xmlBufferPtr target;
4246 const xmlChar *point;
4247 int offset;
4248
4249 CHECK_ARITY(2);
4250 CAST_TO_STRING;
4251 find = valuePop(ctxt);
4252 CAST_TO_STRING;
4253 str = valuePop(ctxt);
4254
4255 target = xmlBufferCreate();
4256 if (target) {
4257 point = xmlStrstr(str->stringval, find->stringval);
4258 if (point) {
4259 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4260 xmlBufferAdd(target, &str->stringval[offset],
4261 xmlStrlen(str->stringval) - offset);
4262 }
4263 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4264 xmlBufferFree(target);
4265 }
4266
4267 xmlXPathFreeObject(str);
4268 xmlXPathFreeObject(find);
4269}
4270
4271/**
4272 * xmlXPathNormalizeFunction:
4273 * @ctxt: the XPath Parser context
4274 * @nargs: the number of arguments
4275 *
4276 * Implement the normalize-space() XPath function
4277 * string normalize-space(string?)
4278 * The normalize-space function returns the argument string with white
4279 * space normalized by stripping leading and trailing whitespace
4280 * and replacing sequences of whitespace characters by a single
4281 * space. Whitespace characters are the same allowed by the S production
4282 * in XML. If the argument is omitted, it defaults to the context
4283 * node converted to a string, in other words the value of the context node.
4284 */
4285void
4286xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4287 xmlXPathObjectPtr obj = NULL;
4288 xmlChar *source = NULL;
4289 xmlBufferPtr target;
4290 xmlChar blank;
4291
4292 if (nargs == 0) {
4293 /* Use current context node */
4294 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4295 xmlXPathStringFunction(ctxt, 1);
4296 nargs = 1;
4297 }
4298
4299 CHECK_ARITY(1);
4300 CAST_TO_STRING;
4301 CHECK_TYPE(XPATH_STRING);
4302 obj = valuePop(ctxt);
4303 source = obj->stringval;
4304
4305 target = xmlBufferCreate();
4306 if (target && source) {
4307
4308 /* Skip leading whitespaces */
4309 while (IS_BLANK(*source))
4310 source++;
4311
4312 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4313 blank = 0;
4314 while (*source) {
4315 if (IS_BLANK(*source)) {
4316 blank = *source;
4317 } else {
4318 if (blank) {
4319 xmlBufferAdd(target, &blank, 1);
4320 blank = 0;
4321 }
4322 xmlBufferAdd(target, source, 1);
4323 }
4324 source++;
4325 }
4326
4327 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4328 xmlBufferFree(target);
4329 }
4330 xmlXPathFreeObject(obj);
4331}
4332
4333/**
4334 * xmlXPathTranslateFunction:
4335 * @ctxt: the XPath Parser context
4336 * @nargs: the number of arguments
4337 *
4338 * Implement the translate() XPath function
4339 * string translate(string, string, string)
4340 * The translate function returns the first argument string with
4341 * occurrences of characters in the second argument string replaced
4342 * by the character at the corresponding position in the third argument
4343 * string. For example, translate("bar","abc","ABC") returns the string
4344 * BAr. If there is a character in the second argument string with no
4345 * character at a corresponding position in the third argument string
4346 * (because the second argument string is longer than the third argument
4347 * string), then occurrences of that character in the first argument
4348 * string are removed. For example, translate("--aaa--","abc-","ABC")
4349 * returns "AAA". If a character occurs more than once in second
4350 * argument string, then the first occurrence determines the replacement
4351 * character. If the third argument string is longer than the second
4352 * argument string, then excess characters are ignored.
4353 */
4354void
4355xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4356 xmlXPathObjectPtr str;
4357 xmlXPathObjectPtr from;
4358 xmlXPathObjectPtr to;
4359 xmlBufferPtr target;
4360 int i, offset, max;
4361 xmlChar ch;
4362 const xmlChar *point;
4363
4364 CHECK_ARITY(3);
4365
4366 CAST_TO_STRING;
4367 to = valuePop(ctxt);
4368 CAST_TO_STRING;
4369 from = valuePop(ctxt);
4370 CAST_TO_STRING;
4371 str = valuePop(ctxt);
4372
4373 target = xmlBufferCreate();
4374 if (target) {
4375 max = xmlStrlen(to->stringval);
4376 for (i = 0; (ch = str->stringval[i]); i++) {
4377 point = xmlStrchr(from->stringval, ch);
4378 if (point) {
4379 /* Warning: This may not work with UTF-8 */
4380 offset = (int)(point - from->stringval);
4381 if (offset < max)
4382 xmlBufferAdd(target, &to->stringval[offset], 1);
4383 } else
4384 xmlBufferAdd(target, &ch, 1);
4385 }
4386 }
4387 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4388 xmlBufferFree(target);
4389 xmlXPathFreeObject(str);
4390 xmlXPathFreeObject(from);
4391 xmlXPathFreeObject(to);
4392}
4393
4394/**
4395 * xmlXPathBooleanFunction:
4396 * @ctxt: the XPath Parser context
4397 * @nargs: the number of arguments
4398 *
4399 * Implement the boolean() XPath function
4400 * boolean boolean(object)
4401 * he boolean function converts its argument to a boolean as follows:
4402 * - a number is true if and only if it is neither positive or
4403 * negative zero nor NaN
4404 * - a node-set is true if and only if it is non-empty
4405 * - a string is true if and only if its length is non-zero
4406 */
4407void
4408xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4409 xmlXPathObjectPtr cur;
4410 int res = 0;
4411
4412 CHECK_ARITY(1);
4413 cur = valuePop(ctxt);
4414 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4415 switch (cur->type) {
4416 case XPATH_NODESET:
4417 case XPATH_XSLT_TREE:
4418 if ((cur->nodesetval == NULL) ||
4419 (cur->nodesetval->nodeNr == 0)) res = 0;
4420 else
4421 res = 1;
4422 break;
4423 case XPATH_STRING:
4424 if ((cur->stringval == NULL) ||
4425 (cur->stringval[0] == 0)) res = 0;
4426 else
4427 res = 1;
4428 break;
4429 case XPATH_BOOLEAN:
4430 valuePush(ctxt, cur);
4431 return;
4432 case XPATH_NUMBER:
4433 if (cur->floatval) res = 1;
4434 break;
4435 default:
4436 STRANGE
4437 }
4438 xmlXPathFreeObject(cur);
4439 valuePush(ctxt, xmlXPathNewBoolean(res));
4440}
4441
4442/**
4443 * xmlXPathNotFunction:
4444 * @ctxt: the XPath Parser context
4445 * @nargs: the number of arguments
4446 *
4447 * Implement the not() XPath function
4448 * boolean not(boolean)
4449 * The not function returns true if its argument is false,
4450 * and false otherwise.
4451 */
4452void
4453xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4454 CHECK_ARITY(1);
4455 CAST_TO_BOOLEAN;
4456 CHECK_TYPE(XPATH_BOOLEAN);
4457 ctxt->value->boolval = ! ctxt->value->boolval;
4458}
4459
4460/**
4461 * xmlXPathTrueFunction:
4462 * @ctxt: the XPath Parser context
4463 * @nargs: the number of arguments
4464 *
4465 * Implement the true() XPath function
4466 * boolean true()
4467 */
4468void
4469xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4470 CHECK_ARITY(0);
4471 valuePush(ctxt, xmlXPathNewBoolean(1));
4472}
4473
4474/**
4475 * xmlXPathFalseFunction:
4476 * @ctxt: the XPath Parser context
4477 * @nargs: the number of arguments
4478 *
4479 * Implement the false() XPath function
4480 * boolean false()
4481 */
4482void
4483xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4484 CHECK_ARITY(0);
4485 valuePush(ctxt, xmlXPathNewBoolean(0));
4486}
4487
4488/**
4489 * xmlXPathLangFunction:
4490 * @ctxt: the XPath Parser context
4491 * @nargs: the number of arguments
4492 *
4493 * Implement the lang() XPath function
4494 * boolean lang(string)
4495 * The lang function returns true or false depending on whether the
4496 * language of the context node as specified by xml:lang attributes
4497 * is the same as or is a sublanguage of the language specified by
4498 * the argument string. The language of the context node is determined
4499 * by the value of the xml:lang attribute on the context node, or, if
4500 * the context node has no xml:lang attribute, by the value of the
4501 * xml:lang attribute on the nearest ancestor of the context node that
4502 * has an xml:lang attribute. If there is no such attribute, then lang
4503 * returns false. If there is such an attribute, then lang returns
4504 * true if the attribute value is equal to the argument ignoring case,
4505 * or if there is some suffix starting with - such that the attribute
4506 * value is equal to the argument ignoring that suffix of the attribute
4507 * value and ignoring case.
4508 */
4509void
4510xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4511 xmlXPathObjectPtr val;
4512 const xmlChar *theLang;
4513 const xmlChar *lang;
4514 int ret = 0;
4515 int i;
4516
4517 CHECK_ARITY(1);
4518 CAST_TO_STRING;
4519 CHECK_TYPE(XPATH_STRING);
4520 val = valuePop(ctxt);
4521 lang = val->stringval;
4522 theLang = xmlNodeGetLang(ctxt->context->node);
4523 if ((theLang != NULL) && (lang != NULL)) {
4524 for (i = 0;lang[i] != 0;i++)
4525 if (toupper(lang[i]) != toupper(theLang[i]))
4526 goto not_equal;
4527 ret = 1;
4528 }
4529not_equal:
4530 xmlXPathFreeObject(val);
4531 valuePush(ctxt, xmlXPathNewBoolean(ret));
4532}
4533
4534/**
4535 * xmlXPathNumberFunction:
4536 * @ctxt: the XPath Parser context
4537 * @nargs: the number of arguments
4538 *
4539 * Implement the number() XPath function
4540 * number number(object?)
4541 */
4542void
4543xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4544 xmlXPathObjectPtr cur;
4545 double res;
4546
4547 if (nargs == 0) {
4548 if (ctxt->context->node == NULL) {
4549 valuePush(ctxt, xmlXPathNewFloat(0.0));
4550 } else {
4551 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4552
4553 res = xmlXPathStringEvalNumber(content);
4554 valuePush(ctxt, xmlXPathNewFloat(res));
4555 xmlFree(content);
4556 }
4557 return;
4558 }
4559
4560 CHECK_ARITY(1);
4561 cur = valuePop(ctxt);
4562 switch (cur->type) {
4563 case XPATH_UNDEFINED:
4564#ifdef DEBUG_EXPR
4565 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4566#endif
4567 valuePush(ctxt, xmlXPathNewFloat(0.0));
4568 break;
4569 case XPATH_XSLT_TREE:
4570 case XPATH_NODESET:
4571 valuePush(ctxt, cur);
4572 xmlXPathStringFunction(ctxt, 1);
4573 cur = valuePop(ctxt);
4574 case XPATH_STRING:
4575 res = xmlXPathStringEvalNumber(cur->stringval);
4576 valuePush(ctxt, xmlXPathNewFloat(res));
4577 xmlXPathFreeObject(cur);
4578 return;
4579 case XPATH_BOOLEAN:
4580 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
4581 else valuePush(ctxt, xmlXPathNewFloat(0.0));
4582 xmlXPathFreeObject(cur);
4583 return;
4584 case XPATH_NUMBER:
4585 valuePush(ctxt, cur);
4586 return;
4587 case XPATH_USERS:
4588 case XPATH_POINT:
4589 case XPATH_RANGE:
4590 case XPATH_LOCATIONSET:
4591 TODO
4592 valuePush(ctxt, xmlXPathNewFloat(0.0));
4593 break;
4594 }
4595 STRANGE
4596}
4597
4598/**
4599 * xmlXPathSumFunction:
4600 * @ctxt: the XPath Parser context
4601 * @nargs: the number of arguments
4602 *
4603 * Implement the sum() XPath function
4604 * number sum(node-set)
4605 * The sum function returns the sum of the values of the nodes in
4606 * the argument node-set.
4607 */
4608void
4609xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4610 xmlXPathObjectPtr cur;
4611 int i;
4612
4613 CHECK_ARITY(1);
4614 if ((ctxt->value == NULL) ||
4615 ((ctxt->value->type != XPATH_NODESET) &&
4616 (ctxt->value->type != XPATH_XSLT_TREE)))
4617 XP_ERROR(XPATH_INVALID_TYPE);
4618 cur = valuePop(ctxt);
4619
4620 if (cur->nodesetval->nodeNr == 0) {
4621 valuePush(ctxt, xmlXPathNewFloat(0.0));
4622 } else {
4623 valuePush(ctxt,
4624 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
4625 xmlXPathNumberFunction(ctxt, 1);
4626 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4627 valuePush(ctxt,
4628 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4629 xmlXPathAddValues(ctxt);
4630 }
4631 }
4632 xmlXPathFreeObject(cur);
4633}
4634
4635/**
4636 * xmlXPathFloorFunction:
4637 * @ctxt: the XPath Parser context
4638 * @nargs: the number of arguments
4639 *
4640 * Implement the floor() XPath function
4641 * number floor(number)
4642 * The floor function returns the largest (closest to positive infinity)
4643 * number that is not greater than the argument and that is an integer.
4644 */
4645void
4646xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4647 CHECK_ARITY(1);
4648 CAST_TO_NUMBER;
4649 CHECK_TYPE(XPATH_NUMBER);
4650#if 0
4651 ctxt->value->floatval = floor(ctxt->value->floatval);
4652#else
4653 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
4654 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
4655#endif
4656}
4657
4658/**
4659 * xmlXPathCeilingFunction:
4660 * @ctxt: the XPath Parser context
4661 * @nargs: the number of arguments
4662 *
4663 * Implement the ceiling() XPath function
4664 * number ceiling(number)
4665 * The ceiling function returns the smallest (closest to negative infinity)
4666 * number that is not less than the argument and that is an integer.
4667 */
4668void
4669xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4670 double f;
4671
4672 CHECK_ARITY(1);
4673 CAST_TO_NUMBER;
4674 CHECK_TYPE(XPATH_NUMBER);
4675
4676#if 0
4677 ctxt->value->floatval = ceil(ctxt->value->floatval);
4678#else
4679 f = (double)((int) ctxt->value->floatval);
4680 if (f != ctxt->value->floatval)
4681 ctxt->value->floatval = f + 1;
4682#endif
4683}
4684
4685/**
4686 * xmlXPathRoundFunction:
4687 * @ctxt: the XPath Parser context
4688 * @nargs: the number of arguments
4689 *
4690 * Implement the round() XPath function
4691 * number round(number)
4692 * The round function returns the number that is closest to the
4693 * argument and that is an integer. If there are two such numbers,
4694 * then the one that is even is returned.
4695 */
4696void
4697xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4698 double f;
4699
4700 CHECK_ARITY(1);
4701 CAST_TO_NUMBER;
4702 CHECK_TYPE(XPATH_NUMBER);
4703
4704 if ((ctxt->value->floatval == xmlXPathNAN) ||
4705 (ctxt->value->floatval == xmlXPathPINF) ||
4706 (ctxt->value->floatval == xmlXPathNINF) ||
4707 (ctxt->value->floatval == 0.0))
4708 return;
4709
4710#if 0
4711 f = floor(ctxt->value->floatval);
4712#else
4713 f = (double)((int) ctxt->value->floatval);
4714#endif
4715 if (ctxt->value->floatval < f + 0.5)
4716 ctxt->value->floatval = f;
4717 else
4718 ctxt->value->floatval = f + 1;
4719}
4720
4721/************************************************************************
4722 * *
4723 * The Parser *
4724 * *
4725 ************************************************************************/
4726
4727/*
4728 * a couple of forward declarations since we use a recursive call based
4729 * implementation.
4730 */
4731void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
4732void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
4733void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
4734#ifdef VMS
4735void xmlXPathEvalRelLocationPath(xmlXPathParserContextPtr ctxt);
4736#define xmlXPathEvalRelativeLocationPath xmlXPathEvalRelLocationPath
4737#else
4738void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
4739#endif
4740
4741/**
4742 * xmlXPathParseNCName:
4743 * @ctxt: the XPath Parser context
4744 *
4745 * parse an XML namespace non qualified name.
4746 *
4747 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
4748 *
4749 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
4750 * CombiningChar | Extender
4751 *
4752 * Returns the namespace name or NULL
4753 */
4754
4755xmlChar *
4756xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
4757 const xmlChar *q;
4758 xmlChar *ret = NULL;
4759
4760 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4761 q = NEXT;
4762
4763 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4764 (CUR == '.') || (CUR == '-') ||
4765 (CUR == '_') ||
4766 (IS_COMBINING(CUR)) ||
4767 (IS_EXTENDER(CUR)))
4768 NEXT;
4769
4770 ret = xmlStrndup(q, CUR_PTR - q);
4771
4772 return(ret);
4773}
4774
4775/**
4776 * xmlXPathParseQName:
4777 * @ctxt: the XPath Parser context
4778 * @prefix: a xmlChar **
4779 *
4780 * parse an XML qualified name
4781 *
4782 * [NS 5] QName ::= (Prefix ':')? LocalPart
4783 *
4784 * [NS 6] Prefix ::= NCName
4785 *
4786 * [NS 7] LocalPart ::= NCName
4787 *
4788 * Returns the function returns the local part, and prefix is updated
4789 * to get the Prefix if any.
4790 */
4791
4792xmlChar *
4793xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
4794 xmlChar *ret = NULL;
4795
4796 *prefix = NULL;
4797 ret = xmlXPathParseNCName(ctxt);
4798 if (CUR == ':') {
4799 *prefix = ret;
4800 NEXT;
4801 ret = xmlXPathParseNCName(ctxt);
4802 }
4803 return(ret);
4804}
4805
4806/**
4807 * xmlXPathParseName:
4808 * @ctxt: the XPath Parser context
4809 *
4810 * parse an XML name
4811 *
4812 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4813 * CombiningChar | Extender
4814 *
4815 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4816 *
4817 * Returns the namespace name or NULL
4818 */
4819
4820xmlChar *
4821xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
4822 const xmlChar *q;
4823 xmlChar *ret = NULL;
4824
4825 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4826 q = NEXT;
4827
4828 /* TODO Make this UTF8 compliant !!! */
4829 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4830 (CUR == '.') || (CUR == '-') ||
4831 (CUR == '_') || (CUR == ':') ||
4832 (IS_COMBINING(CUR)) ||
4833 (IS_EXTENDER(CUR)))
4834 NEXT;
4835
4836 ret = xmlStrndup(q, CUR_PTR - q);
4837
4838 return(ret);
4839}
4840
4841/**
4842 * xmlXPathStringEvalNumber:
4843 * @str: A string to scan
4844 *
4845 * [30] Number ::= Digits ('.' Digits?)?
4846 * | '.' Digits
4847 * [31] Digits ::= [0-9]+
4848 *
4849 * Parse and evaluate a Number in the string
4850 * In complement of the Number expression, this function also handles
4851 * negative values : '-' Number.
4852 *
4853 * Returns the double value.
4854 */
4855double
4856xmlXPathStringEvalNumber(const xmlChar *str) {
4857 const xmlChar *cur = str;
4858 double ret = 0.0;
4859 double mult = 1;
4860 int ok = 0;
4861 int isneg = 0;
4862
4863 while (IS_BLANK(*cur)) cur++;
4864 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
4865 return(xmlXPathNAN);
4866 }
4867 if (*cur == '-') {
4868 isneg = 1;
4869 cur++;
4870 }
4871 while ((*cur >= '0') && (*cur <= '9')) {
4872 ret = ret * 10 + (*cur - '0');
4873 ok = 1;
4874 cur++;
4875 }
4876 if (*cur == '.') {
4877 cur++;
4878 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
4879 return(xmlXPathNAN);
4880 }
4881 while ((*cur >= '0') && (*cur <= '9')) {
4882 mult /= 10;
4883 ret = ret + (*cur - '0') * mult;
4884 cur++;
4885 }
4886 }
4887 while (IS_BLANK(*cur)) cur++;
4888 if (*cur != 0) return(xmlXPathNAN);
4889 if (isneg) ret = -ret;
4890 return(ret);
4891}
4892
4893/**
4894 * xmlXPathEvalNumber:
4895 * @ctxt: the XPath Parser context
4896 *
4897 * [30] Number ::= Digits ('.' Digits?)?
4898 * | '.' Digits
4899 * [31] Digits ::= [0-9]+
4900 *
4901 * Parse and evaluate a Number, then push it on the stack
4902 *
4903 */
4904void
4905xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
4906 double ret = 0.0;
4907 double mult = 1;
4908 int ok = 0;
4909
4910 CHECK_ERROR;
4911 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
4912 XP_ERROR(XPATH_NUMBER_ERROR);
4913 }
4914 while ((CUR >= '0') && (CUR <= '9')) {
4915 ret = ret * 10 + (CUR - '0');
4916 ok = 1;
4917 NEXT;
4918 }
4919 if (CUR == '.') {
4920 NEXT;
4921 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
4922 XP_ERROR(XPATH_NUMBER_ERROR);
4923 }
4924 while ((CUR >= '0') && (CUR <= '9')) {
4925 mult /= 10;
4926 ret = ret + (CUR - '0') * mult;
4927 NEXT;
4928 }
4929 }
4930 valuePush(ctxt, xmlXPathNewFloat(ret));
4931}
4932
4933/**
4934 * xmlXPathEvalLiteral:
4935 * @ctxt: the XPath Parser context
4936 *
4937 * Parse a Literal and push it on the stack.
4938 *
4939 * [29] Literal ::= '"' [^"]* '"'
4940 * | "'" [^']* "'"
4941 *
4942 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
4943 */
4944void
4945xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
4946 const xmlChar *q;
4947 xmlChar *ret = NULL;
4948
4949 if (CUR == '"') {
4950 NEXT;
4951 q = CUR_PTR;
4952 while ((IS_CHAR(CUR)) && (CUR != '"'))
4953 NEXT;
4954 if (!IS_CHAR(CUR)) {
4955 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
4956 } else {
4957 ret = xmlStrndup(q, CUR_PTR - q);
4958 NEXT;
4959 }
4960 } else if (CUR == '\'') {
4961 NEXT;
4962 q = CUR_PTR;
4963 while ((IS_CHAR(CUR)) && (CUR != '\''))
4964 NEXT;
4965 if (!IS_CHAR(CUR)) {
4966 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
4967 } else {
4968 ret = xmlStrndup(q, CUR_PTR - q);
4969 NEXT;
4970 }
4971 } else {
4972 XP_ERROR(XPATH_START_LITERAL_ERROR);
4973 }
4974 if (ret == NULL) return;
4975 valuePush(ctxt, xmlXPathNewString(ret));
4976 xmlFree(ret);
4977}
4978
4979/**
4980 * xmlXPathEvalVariableReference:
4981 * @ctxt: the XPath Parser context
4982 *
4983 * Parse a VariableReference, evaluate it and push it on the stack.
4984 *
4985 * The variable bindings consist of a mapping from variable names
4986 * to variable values. The value of a variable is an object, which
4987 * of any of the types that are possible for the value of an expression,
4988 * and may also be of additional types not specified here.
4989 *
4990 * Early evaluation is possible since:
4991 * The variable bindings [...] used to evaluate a subexpression are
4992 * always the same as those used to evaluate the containing expression.
4993 *
4994 * [36] VariableReference ::= '$' QName
4995 */
4996void
4997xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
4998 xmlChar *name;
4999 xmlChar *prefix;
5000 xmlXPathObjectPtr value;
5001
5002 SKIP_BLANKS;
5003 if (CUR != '$') {
5004 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5005 }
5006 NEXT;
5007 name = xmlXPathParseQName(ctxt, &prefix);
5008 if (name == NULL) {
5009 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5010 }
5011 if (prefix == NULL) {
5012 value = xmlXPathVariableLookup(ctxt->context, name);
5013 } else {
5014 TODO;
5015 value = NULL;
5016 }
5017 xmlFree(name);
5018 if (prefix != NULL) xmlFree(prefix);
5019 if (value == NULL) {
5020 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
5021 }
5022 valuePush(ctxt, value);
5023 SKIP_BLANKS;
5024}
5025
5026/**
5027 * xmlXPathIsNodeType:
5028 * @ctxt: the XPath Parser context
5029 * @name: a name string
5030 *
5031 * Is the name given a NodeType one.
5032 *
5033 * [38] NodeType ::= 'comment'
5034 * | 'text'
5035 * | 'processing-instruction'
5036 * | 'node'
5037 *
5038 * Returns 1 if true 0 otherwise
5039 */
5040int
5041xmlXPathIsNodeType(const xmlChar *name) {
5042 if (name == NULL)
5043 return(0);
5044
5045 if (xmlStrEqual(name, BAD_CAST "comment"))
5046 return(1);
5047 if (xmlStrEqual(name, BAD_CAST "text"))
5048 return(1);
5049 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5050 return(1);
5051 if (xmlStrEqual(name, BAD_CAST "node"))
5052 return(1);
5053 return(0);
5054}
5055
5056/**
5057 * xmlXPathEvalFunctionCall:
5058 * @ctxt: the XPath Parser context
5059 *
5060 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5061 * [17] Argument ::= Expr
5062 *
5063 * Parse and evaluate a function call, the evaluation of all arguments are
5064 * pushed on the stack
5065 */
5066void
5067xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
5068 xmlChar *name;
5069 xmlChar *prefix;
5070 xmlXPathFunction func;
5071 int nbargs = 0;
5072
5073 name = xmlXPathParseQName(ctxt, &prefix);
5074 if (name == NULL) {
5075 XP_ERROR(XPATH_EXPR_ERROR);
5076 }
5077 SKIP_BLANKS;
5078 if (prefix == NULL) {
5079 func = xmlXPathFunctionLookup(ctxt->context, name);
5080 } else {
5081 TODO;
5082 func = NULL;
5083 }
5084 if (func == NULL) {
5085 xmlFree(name);
5086 if (prefix != NULL) xmlFree(prefix);
5087 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
5088 }
5089#ifdef DEBUG_EXPR
5090 if (prefix == NULL)
5091 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5092 name);
5093 else
5094 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5095 prefix, name);
5096#endif
5097
5098 xmlFree(name);
5099 if (prefix != NULL) xmlFree(prefix);
5100
5101 if (CUR != '(') {
5102 XP_ERROR(XPATH_EXPR_ERROR);
5103 }
5104 NEXT;
5105 SKIP_BLANKS;
5106
5107 while (CUR != ')') {
5108 xmlXPathEvalExpr(ctxt);
5109 nbargs++;
5110 if (CUR == ')') break;
5111 if (CUR != ',') {
5112 XP_ERROR(XPATH_EXPR_ERROR);
5113 }
5114 NEXT;
5115 SKIP_BLANKS;
5116 }
5117 NEXT;
5118 SKIP_BLANKS;
5119 func(ctxt, nbargs);
5120}
5121
5122/**
5123 * xmlXPathEvalPrimaryExpr:
5124 * @ctxt: the XPath Parser context
5125 *
5126 * [15] PrimaryExpr ::= VariableReference
5127 * | '(' Expr ')'
5128 * | Literal
5129 * | Number
5130 * | FunctionCall
5131 *
5132 * Parse and evaluate a primary expression, then push the result on the stack
5133 */
5134void
5135xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
5136 SKIP_BLANKS;
5137 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
5138 else if (CUR == '(') {
5139 NEXT;
5140 SKIP_BLANKS;
5141 xmlXPathEvalExpr(ctxt);
5142 if (CUR != ')') {
5143 XP_ERROR(XPATH_EXPR_ERROR);
5144 }
5145 NEXT;
5146 SKIP_BLANKS;
5147 } else if (IS_DIGIT(CUR)) {
5148 xmlXPathEvalNumber(ctxt);
5149 } else if ((CUR == '\'') || (CUR == '"')) {
5150 xmlXPathEvalLiteral(ctxt);
5151 } else {
5152 xmlXPathEvalFunctionCall(ctxt);
5153 }
5154 SKIP_BLANKS;
5155}
5156
5157/**
5158 * xmlXPathEvalFilterExpr:
5159 * @ctxt: the XPath Parser context
5160 *
5161 * [20] FilterExpr ::= PrimaryExpr
5162 * | FilterExpr Predicate
5163 *
5164 * Parse and evaluate a filter expression, then push the result on the stack
5165 * Square brackets are used to filter expressions in the same way that
5166 * they are used in location paths. It is an error if the expression to
5167 * be filtered does not evaluate to a node-set. The context node list
5168 * used for evaluating the expression in square brackets is the node-set
5169 * to be filtered listed in document order.
5170 */
5171
5172void
5173xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
5174 xmlXPathEvalPrimaryExpr(ctxt);
5175 CHECK_ERROR;
5176 SKIP_BLANKS;
5177
5178 while (CUR == '[') {
5179 if ((ctxt->value == NULL) ||
5180 ((ctxt->value->type != XPATH_NODESET) &&
5181 (ctxt->value->type != XPATH_LOCATIONSET)))
5182 XP_ERROR(XPATH_INVALID_TYPE)
5183
5184 if (ctxt->value->type == XPATH_NODESET)
5185 xmlXPathEvalPredicate(ctxt);
5186 else
5187 xmlXPtrEvalRangePredicate(ctxt);
5188 SKIP_BLANKS;
5189 }
5190
5191
5192}
5193
5194/**
5195 * xmlXPathScanName:
5196 * @ctxt: the XPath Parser context
5197 *
5198 * Trickery: parse an XML name but without consuming the input flow
5199 * Needed to avoid insanity in the parser state.
5200 *
5201 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5202 * CombiningChar | Extender
5203 *
5204 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5205 *
5206 * [6] Names ::= Name (S Name)*
5207 *
5208 * Returns the Name parsed or NULL
5209 */
5210
5211xmlChar *
5212xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
5213 xmlChar buf[XML_MAX_NAMELEN];
5214 int len = 0;
5215
5216 SKIP_BLANKS;
5217 if (!IS_LETTER(CUR) && (CUR != '_') &&
5218 (CUR != ':')) {
5219 return(NULL);
5220 }
5221
5222 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5223 (NXT(len) == '.') || (NXT(len) == '-') ||
5224 (NXT(len) == '_') || (NXT(len) == ':') ||
5225 (IS_COMBINING(NXT(len))) ||
5226 (IS_EXTENDER(NXT(len)))) {
5227 buf[len] = NXT(len);
5228 len++;
5229 if (len >= XML_MAX_NAMELEN) {
5230 xmlGenericError(xmlGenericErrorContext,
5231 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5232 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5233 (NXT(len) == '.') || (NXT(len) == '-') ||
5234 (NXT(len) == '_') || (NXT(len) == ':') ||
5235 (IS_COMBINING(NXT(len))) ||
5236 (IS_EXTENDER(NXT(len))))
5237 len++;
5238 break;
5239 }
5240 }
5241 return(xmlStrndup(buf, len));
5242}
5243
5244/**
5245 * xmlXPathEvalPathExpr:
5246 * @ctxt: the XPath Parser context
5247 *
5248 * [19] PathExpr ::= LocationPath
5249 * | FilterExpr
5250 * | FilterExpr '/' RelativeLocationPath
5251 * | FilterExpr '//' RelativeLocationPath
5252 *
5253 * Parse and evaluate a path expression, then push the result on the stack
5254 * The / operator and // operators combine an arbitrary expression
5255 * and a relative location path. It is an error if the expression
5256 * does not evaluate to a node-set.
5257 * The / operator does composition in the same way as when / is
5258 * used in a location path. As in location paths, // is short for
5259 * /descendant-or-self::node()/.
5260 */
5261
5262void
5263xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
5264 int lc = 1; /* Should we branch to LocationPath ? */
5265 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5266
5267 SKIP_BLANKS;
5268 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5269 (CUR == '\'') || (CUR == '"')) {
5270 lc = 0;
5271 } else if (CUR == '*') {
5272 /* relative or absolute location path */
5273 lc = 1;
5274 } else if (CUR == '/') {
5275 /* relative or absolute location path */
5276 lc = 1;
5277 } else if (CUR == '@') {
5278 /* relative abbreviated attribute location path */
5279 lc = 1;
5280 } else if (CUR == '.') {
5281 /* relative abbreviated attribute location path */
5282 lc = 1;
5283 } else {
5284 /*
5285 * Problem is finding if we have a name here whether it's:
5286 * - a nodetype
5287 * - a function call in which case it's followed by '('
5288 * - an axis in which case it's followed by ':'
5289 * - a element name
5290 * We do an a priori analysis here rather than having to
5291 * maintain parsed token content through the recursive function
5292 * calls. This looks uglier but makes the code quite easier to
5293 * read/write/debug.
5294 */
5295 SKIP_BLANKS;
5296 name = xmlXPathScanName(ctxt);
5297 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
5298#ifdef DEBUG_STEP
5299 xmlGenericError(xmlGenericErrorContext,
5300 "PathExpr: Axis\n");
5301#endif
5302 lc = 1;
5303 xmlFree(name);
5304 } else if (name != NULL) {
5305 int len =xmlStrlen(name);
5306 int blank = 0;
5307
5308
5309 while (NXT(len) != 0) {
5310 if (NXT(len) == '/') {
5311 /* element name */
5312#ifdef DEBUG_STEP
5313 xmlGenericError(xmlGenericErrorContext,
5314 "PathExpr: AbbrRelLocation\n");
5315#endif
5316 lc = 1;
5317 break;
5318 } else if (IS_BLANK(NXT(len))) {
5319 /* skip to next */
5320 blank = 1;
5321 } else if (NXT(len) == ':') {
5322#ifdef DEBUG_STEP
5323 xmlGenericError(xmlGenericErrorContext,
5324 "PathExpr: AbbrRelLocation\n");
5325#endif
5326 lc = 1;
5327 break;
5328 } else if ((NXT(len) == '(')) {
5329 /* Note Type or Function */
5330 if (xmlXPathIsNodeType(name)) {
5331#ifdef DEBUG_STEP
5332 xmlGenericError(xmlGenericErrorContext,
5333 "PathExpr: Type search\n");
5334#endif
5335 lc = 1;
5336 } else {
5337#ifdef DEBUG_STEP
5338 xmlGenericError(xmlGenericErrorContext,
5339 "PathExpr: function call\n");
5340#endif
5341 lc = 0;
5342 }
5343 break;
5344 } else if ((NXT(len) == '[')) {
5345 /* element name */
5346#ifdef DEBUG_STEP
5347 xmlGenericError(xmlGenericErrorContext,
5348 "PathExpr: AbbrRelLocation\n");
5349#endif
5350 lc = 1;
5351 break;
5352 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5353 (NXT(len) == '=')) {
5354 lc = 1;
5355 break;
5356 } else {
5357 lc = 1;
5358 break;
5359 }
5360 len++;
5361 }
5362 if (NXT(len) == 0) {
5363#ifdef DEBUG_STEP
5364 xmlGenericError(xmlGenericErrorContext,
5365 "PathExpr: AbbrRelLocation\n");
5366#endif
5367 /* element name */
5368 lc = 1;
5369 }
5370 xmlFree(name);
5371 } else {
5372 /* make sure all cases are covered explicitely */
5373 XP_ERROR(XPATH_EXPR_ERROR);
5374 }
5375 }
5376
5377 if (lc) {
5378 if (CUR == '/')
5379 xmlXPathRoot(ctxt);
5380 else {
5381 /* TAG:9999 */
5382 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5383 }
5384 xmlXPathEvalLocationPath(ctxt);
5385 } else {
5386 xmlXPathEvalFilterExpr(ctxt);
5387 CHECK_ERROR;
5388 if ((CUR == '/') && (NXT(1) == '/')) {
5389 SKIP(2);
5390 SKIP_BLANKS;
5391 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
5392 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
5393 ctxt->context->node = NULL;
5394 xmlXPathEvalRelativeLocationPath(ctxt);
5395 } else if (CUR == '/') {
5396 xmlXPathEvalRelativeLocationPath(ctxt);
5397 }
5398 }
5399 SKIP_BLANKS;
5400}
5401
5402/**
5403 * xmlXPathEvalUnionExpr:
5404 * @ctxt: the XPath Parser context
5405 *
5406 * [18] UnionExpr ::= PathExpr
5407 * | UnionExpr '|' PathExpr
5408 *
5409 * Parse and evaluate an union expression, then push the result on the stack
5410 */
5411
5412void
5413xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
5414 int sort = 0;
5415 xmlXPathEvalPathExpr(ctxt);
5416 CHECK_ERROR;
5417 SKIP_BLANKS;
5418 while (CUR == '|') {
5419 xmlXPathObjectPtr obj1,obj2, tmp;
5420
5421 sort = 1;
5422 CHECK_TYPE(XPATH_NODESET);
5423 obj1 = valuePop(ctxt);
5424 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5425 valuePush(ctxt, tmp);
5426
5427 NEXT;
5428 SKIP_BLANKS;
5429 xmlXPathEvalPathExpr(ctxt);
5430
5431 CHECK_TYPE(XPATH_NODESET);
5432 obj2 = valuePop(ctxt);
5433 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
5434 obj2->nodesetval);
5435 if (ctxt->value == tmp) {
5436 tmp = valuePop(ctxt);
5437 xmlXPathFreeObject(tmp);
5438 }
5439 valuePush(ctxt, obj1);
5440 xmlXPathFreeObject(obj2);
5441 SKIP_BLANKS;
5442 }
5443 if (sort) {
5444 }
5445}
5446
5447/**
5448 * xmlXPathEvalUnaryExpr:
5449 * @ctxt: the XPath Parser context
5450 *
5451 * [27] UnaryExpr ::= UnionExpr
5452 * | '-' UnaryExpr
5453 *
5454 * Parse and evaluate an unary expression, then push the result on the stack
5455 */
5456
5457void
5458xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
5459 int minus = 0;
5460
5461 SKIP_BLANKS;
5462 if (CUR == '-') {
5463 minus = 1;
5464 NEXT;
5465 SKIP_BLANKS;
5466 }
5467 xmlXPathEvalUnionExpr(ctxt);
5468 CHECK_ERROR;
5469 if (minus) {
5470 xmlXPathValueFlipSign(ctxt);
5471 }
5472}
5473
5474/**
5475 * xmlXPathEvalMultiplicativeExpr:
5476 * @ctxt: the XPath Parser context
5477 *
5478 * [26] MultiplicativeExpr ::= UnaryExpr
5479 * | MultiplicativeExpr MultiplyOperator UnaryExpr
5480 * | MultiplicativeExpr 'div' UnaryExpr
5481 * | MultiplicativeExpr 'mod' UnaryExpr
5482 * [34] MultiplyOperator ::= '*'
5483 *
5484 * Parse and evaluate an Additive expression, then push the result on the stack
5485 */
5486
5487void
5488xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
5489 xmlXPathEvalUnaryExpr(ctxt);
5490 CHECK_ERROR;
5491 SKIP_BLANKS;
5492 while ((CUR == '*') ||
5493 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
5494 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
5495 int op = -1;
5496
5497 if (CUR == '*') {
5498 op = 0;
5499 NEXT;
5500 } else if (CUR == 'd') {
5501 op = 1;
5502 SKIP(3);
5503 } else if (CUR == 'm') {
5504 op = 2;
5505 SKIP(3);
5506 }
5507 SKIP_BLANKS;
5508 xmlXPathEvalUnaryExpr(ctxt);
5509 CHECK_ERROR;
5510 switch (op) {
5511 case 0:
5512 xmlXPathMultValues(ctxt);
5513 break;
5514 case 1:
5515 xmlXPathDivValues(ctxt);
5516 break;
5517 case 2:
5518 xmlXPathModValues(ctxt);
5519 break;
5520 }
5521 SKIP_BLANKS;
5522 }
5523}
5524
5525/**
5526 * xmlXPathEvalAdditiveExpr:
5527 * @ctxt: the XPath Parser context
5528 *
5529 * [25] AdditiveExpr ::= MultiplicativeExpr
5530 * | AdditiveExpr '+' MultiplicativeExpr
5531 * | AdditiveExpr '-' MultiplicativeExpr
5532 *
5533 * Parse and evaluate an Additive expression, then push the result on the stack
5534 */
5535
5536void
5537xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
5538 xmlXPathEvalMultiplicativeExpr(ctxt);
5539 CHECK_ERROR;
5540 SKIP_BLANKS;
5541 while ((CUR == '+') || (CUR == '-')) {
5542 int plus;
5543
5544 if (CUR == '+') plus = 1;
5545 else plus = 0;
5546 NEXT;
5547 SKIP_BLANKS;
5548 xmlXPathEvalMultiplicativeExpr(ctxt);
5549 CHECK_ERROR;
5550 if (plus) xmlXPathAddValues(ctxt);
5551 else xmlXPathSubValues(ctxt);
5552 SKIP_BLANKS;
5553 }
5554}
5555
5556/**
5557 * xmlXPathEvalRelationalExpr:
5558 * @ctxt: the XPath Parser context
5559 *
5560 * [24] RelationalExpr ::= AdditiveExpr
5561 * | RelationalExpr '<' AdditiveExpr
5562 * | RelationalExpr '>' AdditiveExpr
5563 * | RelationalExpr '<=' AdditiveExpr
5564 * | RelationalExpr '>=' AdditiveExpr
5565 *
5566 * A <= B > C is allowed ? Answer from James, yes with
5567 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
5568 * which is basically what got implemented.
5569 *
5570 * Parse and evaluate a Relational expression, then push the result
5571 * on the stack
5572 */
5573
5574void
5575xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
5576 xmlXPathEvalAdditiveExpr(ctxt);
5577 CHECK_ERROR;
5578 SKIP_BLANKS;
5579 while ((CUR == '<') ||
5580 (CUR == '>') ||
5581 ((CUR == '<') && (NXT(1) == '=')) ||
5582 ((CUR == '>') && (NXT(1) == '='))) {
5583 int inf, strict, ret;
5584
5585 if (CUR == '<') inf = 1;
5586 else inf = 0;
5587 if (NXT(1) == '=') strict = 0;
5588 else strict = 1;
5589 NEXT;
5590 if (!strict) NEXT;
5591 SKIP_BLANKS;
5592 xmlXPathEvalAdditiveExpr(ctxt);
5593 CHECK_ERROR;
5594 ret = xmlXPathCompareValues(ctxt, inf, strict);
5595 valuePush(ctxt, xmlXPathNewBoolean(ret));
5596 SKIP_BLANKS;
5597 }
5598}
5599
5600/**
5601 * xmlXPathEvalEqualityExpr:
5602 * @ctxt: the XPath Parser context
5603 *
5604 * [23] EqualityExpr ::= RelationalExpr
5605 * | EqualityExpr '=' RelationalExpr
5606 * | EqualityExpr '!=' RelationalExpr
5607 *
5608 * A != B != C is allowed ? Answer from James, yes with
5609 * (RelationalExpr = RelationalExpr) = RelationalExpr
5610 * (RelationalExpr != RelationalExpr) != RelationalExpr
5611 * which is basically what got implemented.
5612 *
5613 * Parse and evaluate an Equality expression, then push the result on the stack
5614 *
5615 */
5616void
5617xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
5618 xmlXPathEvalRelationalExpr(ctxt);
5619 CHECK_ERROR;
5620 SKIP_BLANKS;
5621 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
5622 xmlXPathObjectPtr res;
5623 int eq, equal;
5624
5625 if (CUR == '=') eq = 1;
5626 else eq = 0;
5627 NEXT;
5628 if (!eq) NEXT;
5629 SKIP_BLANKS;
5630 xmlXPathEvalRelationalExpr(ctxt);
5631 CHECK_ERROR;
5632 equal = xmlXPathEqualValues(ctxt);
5633 if (eq) res = xmlXPathNewBoolean(equal);
5634 else res = xmlXPathNewBoolean(!equal);
5635 valuePush(ctxt, res);
5636 SKIP_BLANKS;
5637 }
5638}
5639
5640/**
5641 * xmlXPathEvalAndExpr:
5642 * @ctxt: the XPath Parser context
5643 *
5644 * [22] AndExpr ::= EqualityExpr
5645 * | AndExpr 'and' EqualityExpr
5646 *
5647 * Parse and evaluate an AND expression, then push the result on the stack
5648 *
5649 */
5650void
5651xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
5652 xmlXPathEvalEqualityExpr(ctxt);
5653 CHECK_ERROR;
5654 SKIP_BLANKS;
5655 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
5656 xmlXPathObjectPtr arg1, arg2;
5657
5658 SKIP(3);
5659 SKIP_BLANKS;
5660 xmlXPathEvalEqualityExpr(ctxt);
5661 CHECK_ERROR;
5662 xmlXPathBooleanFunction(ctxt, 1);
5663 arg2 = valuePop(ctxt);
5664 xmlXPathBooleanFunction(ctxt, 1);
5665 arg1 = valuePop(ctxt);
5666 arg1->boolval &= arg2->boolval;
5667 valuePush(ctxt, arg1);
5668 xmlXPathFreeObject(arg2);
5669 SKIP_BLANKS;
5670 }
5671}
5672
5673/**
5674 * xmlXPathEvalExpr:
5675 * @ctxt: the XPath Parser context
5676 *
5677 * [14] Expr ::= OrExpr
5678 * [21] OrExpr ::= AndExpr
5679 * | OrExpr 'or' AndExpr
5680 *
5681 * Parse and evaluate an expression, then push the result on the stack
5682 *
5683 */
5684void
5685xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
5686 xmlXPathEvalAndExpr(ctxt);
5687 CHECK_ERROR;
5688 SKIP_BLANKS;
5689 while ((CUR == 'o') && (NXT(1) == 'r')) {
5690 xmlXPathObjectPtr arg1, arg2;
5691
5692 SKIP(2);
5693 SKIP_BLANKS;
5694 xmlXPathEvalAndExpr(ctxt);
5695 CHECK_ERROR;
5696 xmlXPathBooleanFunction(ctxt, 1);
5697 arg2 = valuePop(ctxt);
5698 xmlXPathBooleanFunction(ctxt, 1);
5699 arg1 = valuePop(ctxt);
5700 arg1->boolval |= arg2->boolval;
5701 valuePush(ctxt, arg1);
5702 xmlXPathFreeObject(arg2);
5703 SKIP_BLANKS;
5704 }
5705 if ((ctxt->value != NULL) && (ctxt->value->type == XPATH_NODESET) &&
5706 (ctxt->value->nodesetval != NULL))
5707 xmlXPathNodeSetSort(ctxt->value->nodesetval);
5708}
5709
5710/**
5711 * xmlXPathEvaluatePredicateResult:
5712 * @ctxt: the XPath Parser context
5713 * @res: the Predicate Expression evaluation result
5714 *
5715 * Evaluate a predicate result for the current node.
5716 * A PredicateExpr is evaluated by evaluating the Expr and converting
5717 * the result to a boolean. If the result is a number, the result will
5718 * be converted to true if the number is equal to the position of the
5719 * context node in the context node list (as returned by the position
5720 * function) and will be converted to false otherwise; if the result
5721 * is not a number, then the result will be converted as if by a call
5722 * to the boolean function.
5723 *
5724 * Return 1 if predicate is true, 0 otherwise
5725 */
5726int
5727xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
5728 xmlXPathObjectPtr res) {
5729 if (res == NULL) return(0);
5730 switch (res->type) {
5731 case XPATH_BOOLEAN:
5732 return(res->boolval);
5733 case XPATH_NUMBER:
5734 return(res->floatval == ctxt->context->proximityPosition);
5735 case XPATH_NODESET:
5736 case XPATH_XSLT_TREE:
5737 return(res->nodesetval->nodeNr != 0);
5738 case XPATH_STRING:
5739 return((res->stringval != NULL) &&
5740 (xmlStrlen(res->stringval) != 0));
5741 default:
5742 STRANGE
5743 }
5744 return(0);
5745}
5746
5747/**
5748 * xmlXPathEvalPredicate:
5749 * @ctxt: the XPath Parser context
5750 *
5751 * [8] Predicate ::= '[' PredicateExpr ']'
5752 * [9] PredicateExpr ::= Expr
5753 *
5754 * ---------------------
5755 * For each node in the node-set to be filtered, the PredicateExpr is
5756 * evaluated with that node as the context node, with the number of nodes
5757 * in the node-set as the context size, and with the proximity position
5758 * of the node in the node-set with respect to the axis as the context
5759 * position; if PredicateExpr evaluates to true for that node, the node
5760 * is included in the new node-set; otherwise, it is not included.
5761 * ---------------------
5762 *
5763 * Parse and evaluate a predicate for all the elements of the
5764 * current node list. Then refine the list by removing all
5765 * nodes where the predicate is false.
5766 */
5767void
5768xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
5769 const xmlChar *cur;
5770 xmlXPathObjectPtr res;
5771 xmlXPathObjectPtr obj, tmp;
5772 xmlNodeSetPtr newset = NULL;
5773 xmlNodeSetPtr oldset;
5774 xmlNodePtr oldnode;
5775 int i;
5776
5777 SKIP_BLANKS;
5778 if (CUR != '[') {
5779 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
5780 }
5781 NEXT;
5782 SKIP_BLANKS;
5783
5784 /*
5785 * Extract the old set, and then evaluate the result of the
5786 * expression for all the element in the set. use it to grow
5787 * up a new set.
5788 */
5789 CHECK_TYPE(XPATH_NODESET);
5790 obj = valuePop(ctxt);
5791 oldset = obj->nodesetval;
5792 oldnode = ctxt->context->node;
5793 ctxt->context->node = NULL;
5794
5795 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
5796 ctxt->context->contextSize = 0;
5797 ctxt->context->proximityPosition = 0;
5798 xmlXPathEvalExpr(ctxt);
5799 res = valuePop(ctxt);
5800 if (res != NULL)
5801 xmlXPathFreeObject(res);
5802 valuePush(ctxt, obj);
5803 CHECK_ERROR;
5804 } else {
5805 /*
5806 * Save the expression pointer since we will have to evaluate
5807 * it multiple times. Initialize the new set.
5808 */
5809 cur = ctxt->cur;
5810 newset = xmlXPathNodeSetCreate(NULL);
5811
5812 for (i = 0; i < oldset->nodeNr; i++) {
5813 ctxt->cur = cur;
5814
5815 /*
5816 * Run the evaluation with a node list made of a single item
5817 * in the nodeset.
5818 */
5819 ctxt->context->node = oldset->nodeTab[i];
5820 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5821 valuePush(ctxt, tmp);
5822 ctxt->context->contextSize = oldset->nodeNr;
5823 ctxt->context->proximityPosition = i + 1;
5824
5825 xmlXPathEvalExpr(ctxt);
5826 CHECK_ERROR;
5827
5828 /*
5829 * The result of the evaluation need to be tested to
5830 * decided whether the filter succeeded or not
5831 */
5832 res = valuePop(ctxt);
5833 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
5834 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
5835 }
5836
5837 /*
5838 * Cleanup
5839 */
5840 if (res != NULL)
5841 xmlXPathFreeObject(res);
5842 if (ctxt->value == tmp) {
5843 res = valuePop(ctxt);
5844 xmlXPathFreeObject(res);
5845 }
5846
5847 ctxt->context->node = NULL;
5848 }
5849
5850 /*
5851 * The result is used as the new evaluation set.
5852 */
5853 xmlXPathFreeObject(obj);
5854 ctxt->context->node = NULL;
5855 ctxt->context->contextSize = -1;
5856 ctxt->context->proximityPosition = -1;
5857 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
5858 }
5859 if (CUR != ']') {
5860 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
5861 }
5862
5863 NEXT;
5864 SKIP_BLANKS;
5865#ifdef DEBUG_STEP
5866 xmlGenericError(xmlGenericErrorContext, "After predicate : ");
5867 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5868 ctxt->value->nodesetval);
5869#endif
5870 ctxt->context->node = oldnode;
5871}
5872
5873/**
5874 * xmlXPathEvalNodeTest:
5875 * @ctxt: the XPath Parser context
5876 * @test: pointer to a xmlXPathTestVal
5877 * @type: pointer to a xmlXPathTypeVal
5878 * @prefix: placeholder for a possible name prefix
5879 *
5880 * [7] NodeTest ::= NameTest
5881 * | NodeType '(' ')'
5882 * | 'processing-instruction' '(' Literal ')'
5883 *
5884 * [37] NameTest ::= '*'
5885 * | NCName ':' '*'
5886 * | QName
5887 * [38] NodeType ::= 'comment'
5888 * | 'text'
5889 * | 'processing-instruction'
5890 * | 'node'
5891 *
5892 * Returns the name found and update @test, @type and @prefix appropriately
5893 */
5894xmlChar *
5895xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
5896 xmlXPathTypeVal *type, const xmlChar **prefix, xmlChar *name) {
5897 int blanks;
5898
5899 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
5900 STRANGE;
5901 return(NULL);
5902 }
5903 *type = 0;
5904 *test = 0;
5905 *prefix = NULL;
5906 SKIP_BLANKS;
5907
5908 if ((name == NULL) && (CUR == '*')) {
5909 /*
5910 * All elements
5911 */
5912 NEXT;
5913 *test = NODE_TEST_ALL;
5914 return(NULL);
5915 }
5916
5917 if (name == NULL)
5918 name = xmlXPathParseNCName(ctxt);
5919 if (name == NULL) {
5920 XP_ERROR0(XPATH_EXPR_ERROR);
5921 }
5922
5923 blanks = IS_BLANK(CUR);
5924 SKIP_BLANKS;
5925 if (CUR == '(') {
5926 NEXT;
5927 /*
5928 * NodeType or PI search
5929 */
5930 if (xmlStrEqual(name, BAD_CAST "comment"))
5931 *type = NODE_TYPE_COMMENT;
5932 else if (xmlStrEqual(name, BAD_CAST "node"))
5933 *type = NODE_TYPE_NODE;
5934 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5935 *type = NODE_TYPE_PI;
5936 else if (xmlStrEqual(name, BAD_CAST "text"))
5937 *type = NODE_TYPE_TEXT;
5938 else {
5939 if (name != NULL)
5940 xmlFree(name);
5941 XP_ERROR0(XPATH_EXPR_ERROR);
5942 }
5943
5944 *test = NODE_TEST_TYPE;
5945
5946 SKIP_BLANKS;
5947 if (*type == NODE_TYPE_PI) {
5948 /*
5949 * Specific case: search a PI by name.
5950 */
5951 xmlXPathObjectPtr cur;
5952
5953 if (name != NULL)
5954 xmlFree(name);
5955
5956 xmlXPathEvalLiteral(ctxt);
5957 CHECK_ERROR 0;
5958 xmlXPathStringFunction(ctxt, 1);
5959 CHECK_ERROR0;
5960 cur = valuePop(ctxt);
5961 name = xmlStrdup(cur->stringval);
5962 xmlXPathFreeObject(cur);
5963 SKIP_BLANKS;
5964 }
5965 if (CUR != ')') {
5966 if (name != NULL)
5967 xmlFree(name);
5968 XP_ERROR0(XPATH_UNCLOSED_ERROR);
5969 }
5970 NEXT;
5971 return(name);
5972 }
5973 *test = NODE_TEST_NAME;
5974 if ((!blanks) && (CUR == ':')) {
5975 NEXT;
5976
5977 /*
5978 * get the namespace name for this prefix
5979 */
5980 *prefix = xmlXPathNsLookup(ctxt->context, name);
5981 if (name != NULL)
5982 xmlFree(name);
5983 if (*prefix == NULL) {
5984 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
5985 }
5986
5987 if (CUR == '*') {
5988 /*
5989 * All elements
5990 */
5991 NEXT;
5992 *test = NODE_TEST_ALL;
5993 return(NULL);
5994 }
5995
5996 name = xmlXPathParseNCName(ctxt);
5997 if (name == NULL) {
5998 XP_ERROR0(XPATH_EXPR_ERROR);
5999 }
6000 }
6001 return(name);
6002}
6003
6004/**
6005 * xmlXPathIsAxisName:
6006 * @name: a preparsed name token
6007 *
6008 * [6] AxisName ::= 'ancestor'
6009 * | 'ancestor-or-self'
6010 * | 'attribute'
6011 * | 'child'
6012 * | 'descendant'
6013 * | 'descendant-or-self'
6014 * | 'following'
6015 * | 'following-sibling'
6016 * | 'namespace'
6017 * | 'parent'
6018 * | 'preceding'
6019 * | 'preceding-sibling'
6020 * | 'self'
6021 *
6022 * Returns the axis or 0
6023 */
6024xmlXPathAxisVal
6025xmlXPathIsAxisName(const xmlChar *name) {
6026 xmlXPathAxisVal ret = 0;
6027 switch (name[0]) {
6028 case 'a':
6029 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6030 ret = AXIS_ANCESTOR;
6031 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6032 ret = AXIS_ANCESTOR_OR_SELF;
6033 if (xmlStrEqual(name, BAD_CAST "attribute"))
6034 ret = AXIS_ATTRIBUTE;
6035 break;
6036 case 'c':
6037 if (xmlStrEqual(name, BAD_CAST "child"))
6038 ret = AXIS_CHILD;
6039 break;
6040 case 'd':
6041 if (xmlStrEqual(name, BAD_CAST "descendant"))
6042 ret = AXIS_DESCENDANT;
6043 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6044 ret = AXIS_DESCENDANT_OR_SELF;
6045 break;
6046 case 'f':
6047 if (xmlStrEqual(name, BAD_CAST "following"))
6048 ret = AXIS_FOLLOWING;
6049 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6050 ret = AXIS_FOLLOWING_SIBLING;
6051 break;
6052 case 'n':
6053 if (xmlStrEqual(name, BAD_CAST "namespace"))
6054 ret = AXIS_NAMESPACE;
6055 break;
6056 case 'p':
6057 if (xmlStrEqual(name, BAD_CAST "parent"))
6058 ret = AXIS_PARENT;
6059 if (xmlStrEqual(name, BAD_CAST "preceding"))
6060 ret = AXIS_PRECEDING;
6061 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6062 ret = AXIS_PRECEDING_SIBLING;
6063 break;
6064 case 's':
6065 if (xmlStrEqual(name, BAD_CAST "self"))
6066 ret = AXIS_SELF;
6067 break;
6068 }
6069 return(ret);
6070}
6071
6072/**
6073 * xmlXPathEvalAxisSpecifier:
6074 * @ctxt: the XPath Parser context
6075 *
6076 *
6077 * Returns the axis found
6078 */
6079xmlXPathAxisVal
6080xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
6081 xmlXPathAxisVal ret = AXIS_CHILD;
6082 int blank = 0;
6083 xmlChar *name;
6084
6085 if (CUR == '@') {
6086 NEXT;
6087 return(AXIS_ATTRIBUTE);
6088 } else {
6089 name = xmlXPathParseNCName(ctxt);
6090 if (name == NULL) {
6091 XP_ERROR0(XPATH_EXPR_ERROR);
6092 }
6093 if (IS_BLANK(CUR))
6094 blank = 1;
6095 SKIP_BLANKS;
6096 if ((CUR == ':') && (NXT(1) == ':')) {
6097 ret = xmlXPathIsAxisName(name);
6098 } else if ((blank) && (CUR == ':'))
6099 XP_ERROR0(XPATH_EXPR_ERROR);
6100
6101 xmlFree(name);
6102 }
6103 return(ret);
6104}
6105
6106/**
6107 * xmlXPathEvalStep:
6108 * @ctxt: the XPath Parser context
6109 *
6110 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6111 * | AbbreviatedStep
6112 *
6113 * [12] AbbreviatedStep ::= '.' | '..'
6114 *
6115 * [5] AxisSpecifier ::= AxisName '::'
6116 * | AbbreviatedAxisSpecifier
6117 *
6118 * [13] AbbreviatedAxisSpecifier ::= '@'?
6119 *
6120 * Modified for XPtr range support as:
6121 *
6122 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6123 * | AbbreviatedStep
6124 * | 'range-to' '(' Expr ')' Predicate*
6125 *
6126 * Evaluate one step in a Location Path
6127 * A location step of . is short for self::node(). This is
6128 * particularly useful in conjunction with //. For example, the
6129 * location path .//para is short for
6130 * self::node()/descendant-or-self::node()/child::para
6131 * and so will select all para descendant elements of the context
6132 * node.
6133 * Similarly, a location step of .. is short for parent::node().
6134 * For example, ../title is short for parent::node()/child::title
6135 * and so will select the title children of the parent of the context
6136 * node.
6137 */
6138void
6139xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
6140 SKIP_BLANKS;
6141 if ((CUR == '.') && (NXT(1) == '.')) {
6142 SKIP(2);
6143 SKIP_BLANKS;
6144 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
6145 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6146 } else if (CUR == '.') {
6147 NEXT;
6148 SKIP_BLANKS;
6149 } else {
6150 xmlChar *name = NULL;
6151 const xmlChar *prefix = NULL;
6152 xmlXPathTestVal test;
6153 xmlXPathAxisVal axis;
6154 xmlXPathTypeVal type;
6155
6156 /*
6157 * The modification needed for XPointer change to the production
6158 */
6159#ifdef LIBXML_XPTR_ENABLED
6160 if (ctxt->context->xptr) {
6161 name = xmlXPathParseNCName(ctxt);
6162 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
6163 xmlFree(name);
6164 SKIP_BLANKS;
6165 if (CUR != '(') {
6166 XP_ERROR(XPATH_EXPR_ERROR);
6167 }
6168 NEXT;
6169 SKIP_BLANKS;
6170
6171 xmlXPtrRangeToFunction(ctxt, 1);
6172 CHECK_ERROR;
6173
6174 SKIP_BLANKS;
6175 if (CUR != ')') {
6176 XP_ERROR(XPATH_EXPR_ERROR);
6177 }
6178 NEXT;
6179 goto eval_predicates;
6180 }
6181 }
6182#endif
6183 if (name == NULL)
6184 name = xmlXPathParseNCName(ctxt);
6185 if (name != NULL) {
6186 axis = xmlXPathIsAxisName(name);
6187 if (axis != 0) {
6188 SKIP_BLANKS;
6189 if ((CUR == ':') && (NXT(1) == ':')) {
6190 SKIP(2);
6191 xmlFree(name);
6192 name = NULL;
6193 } else {
6194 /* an element name can conflict with an axis one :-\ */
6195 axis = AXIS_CHILD;
6196 }
6197 } else {
6198 axis = AXIS_CHILD;
6199 }
6200 } else if (CUR == '@') {
6201 NEXT;
6202 axis = AXIS_ATTRIBUTE;
6203 } else {
6204 axis = AXIS_CHILD;
6205 }
6206
6207 CHECK_ERROR;
6208
6209 name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
6210 if (test == 0)
6211 return;
6212
6213#ifdef DEBUG_STEP
6214 xmlGenericError(xmlGenericErrorContext,
6215 "Basis : computing new set\n");
6216#endif
6217 xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
6218#ifdef DEBUG_STEP
6219 xmlGenericError(xmlGenericErrorContext, "Basis : ");
6220 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
6221#endif
6222 if (name != NULL)
6223 xmlFree(name);
6224
6225eval_predicates:
6226 SKIP_BLANKS;
6227 while (CUR == '[') {
6228 xmlXPathEvalPredicate(ctxt);
6229 }
6230 }
6231#ifdef DEBUG_STEP
6232 xmlGenericError(xmlGenericErrorContext, "Step : ");
6233 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6234 ctxt->value->nodesetval);
6235#endif
6236}
6237
6238/**
6239 * xmlXPathEvalRelativeLocationPath:
6240 * @ctxt: the XPath Parser context
6241 *
6242 * [3] RelativeLocationPath ::= Step
6243 * | RelativeLocationPath '/' Step
6244 * | AbbreviatedRelativeLocationPath
6245 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6246 *
6247 */
6248void
6249#ifdef VMS
6250xmlXPathEvalRelLocationPath
6251#else
6252xmlXPathEvalRelativeLocationPath
6253#endif
6254(xmlXPathParserContextPtr ctxt) {
6255 SKIP_BLANKS;
6256 if ((CUR == '/') && (NXT(1) == '/')) {
6257 SKIP(2);
6258 SKIP_BLANKS;
6259 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
6260 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6261 } else if (CUR == '/') {
6262 NEXT;
6263 SKIP_BLANKS;
6264 }
6265 xmlXPathEvalStep(ctxt);
6266 SKIP_BLANKS;
6267 while (CUR == '/') {
6268 if ((CUR == '/') && (NXT(1) == '/')) {
6269 SKIP(2);
6270 SKIP_BLANKS;
6271 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
6272 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6273 xmlXPathEvalStep(ctxt);
6274 } else if (CUR == '/') {
6275 NEXT;
6276 SKIP_BLANKS;
6277 xmlXPathEvalStep(ctxt);
6278 }
6279 SKIP_BLANKS;
6280 }
6281}
6282
6283/**
6284 * xmlXPathEvalLocationPath:
6285 * @ctxt: the XPath Parser context
6286 *
6287 * [1] LocationPath ::= RelativeLocationPath
6288 * | AbsoluteLocationPath
6289 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6290 * | AbbreviatedAbsoluteLocationPath
6291 * [10] AbbreviatedAbsoluteLocationPath ::=
6292 * '//' RelativeLocationPath
6293 *
6294 * // is short for /descendant-or-self::node()/. For example,
6295 * //para is short for /descendant-or-self::node()/child::para and
6296 * so will select any para element in the document (even a para element
6297 * that is a document element will be selected by //para since the
6298 * document element node is a child of the root node); div//para is
6299 * short for div/descendant-or-self::node()/child::para and so will
6300 * select all para descendants of div children.
6301 */
6302void
6303xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
6304 SKIP_BLANKS;
6305 if (CUR != '/') {
6306 xmlXPathEvalRelativeLocationPath(ctxt);
6307 } else {
6308 while (CUR == '/') {
6309 if ((CUR == '/') && (NXT(1) == '/')) {
6310 SKIP(2);
6311 SKIP_BLANKS;
6312 xmlXPathNodeCollectAndTest(ctxt,
6313 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
6314 NODE_TYPE_NODE, NULL, NULL);
6315 xmlXPathEvalRelativeLocationPath(ctxt);
6316 } else if (CUR == '/') {
6317 NEXT;
6318 SKIP_BLANKS;
6319 if (CUR != 0)
6320 xmlXPathEvalRelativeLocationPath(ctxt);
6321 }
6322 }
6323 }
6324}
6325
6326/**
6327 * xmlXPathEval:
6328 * @str: the XPath expression
6329 * @ctx: the XPath context
6330 *
6331 * Evaluate the XPath Location Path in the given context.
6332 *
6333 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
6334 * the caller has to free the object.
6335 */
6336xmlXPathObjectPtr
6337xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
6338 xmlXPathParserContextPtr ctxt;
6339 xmlXPathObjectPtr res, tmp, init = NULL;
6340 int stack = 0;
6341
6342 xmlXPathInit();
6343
6344 CHECK_CONTEXT(ctx)
6345
6346 ctxt = xmlXPathNewParserContext(str, ctx);
6347 /**** TAG:9999
6348 if (ctx->node != NULL) {
6349 init = xmlXPathNewNodeSet(ctx->node);
6350 valuePush(ctxt, init);
6351 }
6352 ****/
6353 xmlXPathEvalExpr(ctxt);
6354
6355 if (ctxt->value == NULL) {
6356 xmlGenericError(xmlGenericErrorContext,
6357 "xmlXPathEval: evaluation failed\n");
6358 res = NULL;
6359 } else if (*ctxt->cur != 0) {
6360 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
6361 res = NULL;
6362 } else {
6363 res = valuePop(ctxt);
6364 }
6365
6366 do {
6367 tmp = valuePop(ctxt);
6368 if (tmp != NULL) {
6369 if (tmp != init)
6370 stack++;
6371 xmlXPathFreeObject(tmp);
6372 }
6373 } while (tmp != NULL);
6374 if ((stack != 0) && (res != NULL)) {
6375 xmlGenericError(xmlGenericErrorContext,
6376 "xmlXPathEval: %d object left on the stack\n",
6377 stack);
6378 }
6379 if (ctxt->error != XPATH_EXPRESSION_OK) {
6380 xmlXPathFreeObject(res);
6381 res = NULL;
6382 }
6383
6384 xmlXPathFreeParserContext(ctxt);
6385 return(res);
6386}
6387
6388/**
6389 * xmlXPathEvalExpression:
6390 * @str: the XPath expression
6391 * @ctxt: the XPath context
6392 *
6393 * Evaluate the XPath expression in the given context.
6394 *
6395 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
6396 * the caller has to free the object.
6397 */
6398xmlXPathObjectPtr
6399xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
6400 xmlXPathParserContextPtr pctxt;
6401 xmlXPathObjectPtr res, tmp;
6402 int stack = 0;
6403
6404 xmlXPathInit();
6405
6406 CHECK_CONTEXT(ctxt)
6407
6408 pctxt = xmlXPathNewParserContext(str, ctxt);
6409 xmlXPathEvalExpr(pctxt);
6410
6411 if (*pctxt->cur != 0) {
6412 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
6413 res = NULL;
6414 } else {
6415 res = valuePop(pctxt);
6416 }
6417 do {
6418 tmp = valuePop(pctxt);
6419 if (tmp != NULL) {
6420 xmlXPathFreeObject(tmp);
6421 stack++;
6422 }
6423 } while (tmp != NULL);
6424 if ((stack != 0) && (res != NULL)) {
6425 xmlGenericError(xmlGenericErrorContext,
6426 "xmlXPathEvalExpression: %d object left on the stack\n",
6427 stack);
6428 }
6429 xmlXPathFreeParserContext(pctxt);
6430 return(res);
6431}
6432
6433/**
6434 * xmlXPathRegisterAllFunctions:
6435 * @ctxt: the XPath context
6436 *
6437 * Registers all default XPath functions in this context
6438 */
6439void
6440xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
6441{
6442 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
6443 xmlXPathBooleanFunction);
6444 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
6445 xmlXPathCeilingFunction);
6446 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
6447 xmlXPathCountFunction);
6448 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
6449 xmlXPathConcatFunction);
6450 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
6451 xmlXPathContainsFunction);
6452 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
6453 xmlXPathIdFunction);
6454 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
6455 xmlXPathFalseFunction);
6456 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
6457 xmlXPathFloorFunction);
6458 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
6459 xmlXPathLastFunction);
6460 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
6461 xmlXPathLangFunction);
6462 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
6463 xmlXPathLocalNameFunction);
6464 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
6465 xmlXPathNotFunction);
6466 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
6467 xmlXPathNameFunction);
6468 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
6469 xmlXPathNamespaceURIFunction);
6470 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
6471 xmlXPathNormalizeFunction);
6472 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
6473 xmlXPathNumberFunction);
6474 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
6475 xmlXPathPositionFunction);
6476 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
6477 xmlXPathRoundFunction);
6478 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
6479 xmlXPathStringFunction);
6480 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
6481 xmlXPathStringLengthFunction);
6482 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
6483 xmlXPathStartsWithFunction);
6484 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
6485 xmlXPathSubstringFunction);
6486 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
6487 xmlXPathSubstringBeforeFunction);
6488 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
6489 xmlXPathSubstringAfterFunction);
6490 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
6491 xmlXPathSumFunction);
6492 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
6493 xmlXPathTrueFunction);
6494 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
6495 xmlXPathTranslateFunction);
6496}
6497
6498#endif /* LIBXML_XPATH_ENABLED */