blob: d6c8f7e555907f12f5d1885c879774369b707227 [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer.
5 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
16#include <malloc.h>
17#include <math.h>
18#include <stdio.h>
19#include "tree.h"
20#include "xpath.h"
21#include "parserInternals.h"
22
23/*
24 * TODO: create a pseudo document element and affect it as the
25 * actual root.
26 */
27/*
28 * That sucks but I couldn't find NAN on a PeeCee Linux Glibc 2.1
29 */
30#ifndef NAN
31#define NAN 12345679
32#endif
33
34/* #define DEBUG */
35/* #define DEBUG_STEP */
36/* #define DEBUG_EXPR */
37
38FILE *xmlXPathDebug = NULL;
39
40#define TODO \
41 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
42 __FILE__, __LINE__);
43
44#define STRANGE \
45 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
46 __FILE__, __LINE__);
47
48float xmlXPathStringEvalNumber(const CHAR *str);
49
50/************************************************************************
51 * *
52 * Parser stacks related functions and macros *
53 * *
54 ************************************************************************/
55
56/*
57 * Generic function for accessing stacks in the Parser Context
58 */
59
60#define PUSH_AND_POP(type, name) \
61extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
62 if (ctxt->name##Nr >= ctxt->name##Max) { \
63 ctxt->name##Max *= 2; \
64 ctxt->name##Tab = (void *) realloc(ctxt->name##Tab, \
65 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
66 if (ctxt->name##Tab == NULL) { \
67 fprintf(xmlXPathDebug, "realloc failed !\n"); \
68 exit(1); \
69 } \
70 } \
71 ctxt->name##Tab[ctxt->name##Nr] = value; \
72 ctxt->name = value; \
73 return(ctxt->name##Nr++); \
74} \
75extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
76 type ret; \
77 if (ctxt->name##Nr <= 0) return(0); \
78 ctxt->name##Nr--; \
79 if (ctxt->name##Nr > 0) \
80 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
81 else \
82 ctxt->name = NULL; \
83 ret = ctxt->name##Tab[ctxt->name##Nr]; \
84 ctxt->name##Tab[ctxt->name##Nr] = 0; \
85 return(ret); \
86} \
87
88PUSH_AND_POP(xmlXPathObjectPtr, value)
89
90/*
91 * Macros for accessing the content. Those should be used only by the parser,
92 * and not exported.
93 *
94 * Dirty macros, i.e. one need to make assumption on the context to use them
95 *
96 * CUR_PTR return the current pointer to the CHAR to be parsed.
97 * CUR returns the current CHAR value, i.e. a 8 bit value if compiled
98 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
99 * in UNICODE mode. This should be used internally by the parser
100 * only to compare to ASCII values otherwise it would break when
101 * running with UTF-8 encoding.
102 * NXT(n) returns the n'th next CHAR. Same as CUR is should be used only
103 * to compare on ASCII based substring.
104 * SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
105 * strings within the parser.
106 * CURRENT Returns the current char value, with the full decoding of
107 * UTF-8 if we are using this mode. It returns an int.
108 * NEXT Skip to the next character, this does the proper decoding
109 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
110 * It returns the pointer to the current CHAR.
111 */
112
113#define CUR (*ctxt->cur)
114#define SKIP(val) ctxt->cur += (val)
115#define NXT(val) ctxt->cur[(val)]
116#define CUR_PTR ctxt->cur
117
118#define SKIP_BLANKS \
119 while (IS_BLANK(*(ctxt->cur))) NEXT
120
121#ifndef USE_UTF_8
122#define CURRENT (*ctxt->cur)
123#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
124#else
125#endif
126
127/************************************************************************
128 * *
129 * Error handling routines *
130 * *
131 ************************************************************************/
132
133#define XPATH_EXPRESSION_OK 0
134#define XPATH_NUMBER_ERROR 1
135#define XPATH_UNFINISHED_LITERAL_ERROR 2
136#define XPATH_START_LITERAL_ERROR 3
137#define XPATH_VARIABLE_REF_ERROR 4
138#define XPATH_UNDEF_VARIABLE_ERROR 5
139#define XPATH_INVALID_PREDICATE_ERROR 6
140#define XPATH_EXPR_ERROR 7
141#define XPATH_UNCLOSED_ERROR 8
142#define XPATH_UNKNOWN_FUNC_ERROR 9
143#define XPATH_INVALID_OPERAND 10
144#define XPATH_INVALID_TYPE 11
145#define XPATH_INVALID_ARITY 12
146
147const char *xmlXPathErrorMessages[] = {
148 "Ok",
149 "Number encoding",
150 "Unfinished litteral",
151 "Start of litteral",
152 "Expected $ for variable reference",
153 "Undefined variable",
154 "Invalid predicate",
155 "Invalid expression",
156 "Missing closing curly brace",
157 "Unregistered function",
158 "Invalid operand",
159 "Invalid type",
160 "Invalid number of arguments",
161};
162
163/**
164 * xmlXPathError:
165 * @ctxt: the XPath Parser context
166 * @file: the file name
167 * @line: the line number
168 * @no: the error number
169 *
170 * Create a new xmlNodeSetPtr of type float and of value @val
171 *
172 * Returns the newly created object.
173 */
174void
175xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
176 int line, int no) {
177 int n;
178 const char *cur;
179 const char *base;
180
181 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
182 xmlXPathErrorMessages[no]);
183
184 cur = ctxt->cur;
185 base = ctxt->base;
186 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
187 cur--;
188 }
189 n = 0;
190 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
191 cur--;
192 if ((*cur == '\n') || (*cur == '\r')) cur++;
193 base = cur;
194 n = 0;
195 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
196 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
197 n++;
198 }
199 fprintf(xmlXPathDebug, "\n");
200 cur = ctxt->cur;
201 while ((*cur == '\n') || (*cur == '\r'))
202 cur--;
203 n = 0;
204 while ((cur != base) && (n++ < 80)) {
205 fprintf(xmlXPathDebug, " ");
206 base++;
207 }
208 fprintf(xmlXPathDebug,"^\n");
209}
210
211#define CHECK_ERROR \
212 if (ctxt->error != XPATH_EXPRESSION_OK) return
213
214#define ERROR(X) \
215 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
216 ctxt->error = (X); return; }
217
218#define CHECK_TYPE(typeval) \
219 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
220 ERROR(XPATH_INVALID_TYPE) \
221
222
223/************************************************************************
224 * *
225 * Routines to handle NodeSets *
226 * *
227 ************************************************************************/
228
229#define XML_NODESET_DEFAULT 10
230/**
231 * xmlXPathNodeSetCreate:
232 * @val: an initial xmlNodePtr, or NULL
233 *
234 * Create a new xmlNodeSetPtr of type float and of value @val
235 *
236 * Returns the newly created object.
237 */
238xmlNodeSetPtr
239xmlXPathNodeSetCreate(xmlNodePtr val) {
240 xmlNodeSetPtr ret;
241
242 ret = (xmlNodeSetPtr) malloc(sizeof(xmlNodeSet));
243 if (ret == NULL) {
244 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
245 return(NULL);
246 }
247 memset(ret, 0 , sizeof(xmlNodeSet));
248 if (val != NULL) {
249 ret->nodeTab = (xmlNodePtr *) malloc(XML_NODESET_DEFAULT *
250 sizeof(xmlNodePtr));
251 if (ret->nodeTab == NULL) {
252 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
253 return(NULL);
254 }
255 memset(ret->nodeTab, 0 ,
256 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
257 ret->nodeMax = XML_NODESET_DEFAULT;
258 ret->nodeTab[ret->nodeNr++] = val;
259 }
260 return(ret);
261}
262
263/**
264 * xmlXPathNodeSetAdd:
265 * @cur: the initial node set
266 * @val: a new xmlNodePtr
267 *
268 * add a new xmlNodePtr ot an existing NodeSet
269 */
270void
271xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
272 int i;
273
274 if (val == NULL) return;
275
276 /*
277 * check against doublons
278 */
279 for (i = 0;i < cur->nodeNr;i++)
280 if (cur->nodeTab[i] == val) return;
281
282 /*
283 * grow the nodeTab if needed
284 */
285 if (cur->nodeMax == 0) {
286 cur->nodeTab = (xmlNodePtr *) malloc(XML_NODESET_DEFAULT *
287 sizeof(xmlNodePtr));
288 if (cur->nodeTab == NULL) {
289 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
290 return;
291 }
292 memset(cur->nodeTab, 0 ,
293 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
294 cur->nodeMax = XML_NODESET_DEFAULT;
295 } else if (cur->nodeNr == cur->nodeMax) {
296 xmlNodePtr *temp;
297
298 cur->nodeMax *= 2;
299 temp = (xmlNodePtr *) realloc(cur->nodeTab, cur->nodeMax *
300 sizeof(xmlNodePtr));
301 if (temp == NULL) {
302 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
303 return;
304 }
305 }
306 cur->nodeTab[cur->nodeNr++] = val;
307}
308
309/**
310 * xmlXPathNodeSetMerge:
311 * @val1: the first NodeSet
312 * @val2: the second NodeSet
313 *
314 * Merges two nodesets, all nodes from @val2 are added to @val1
315 *
316 * Returns val1 once extended or NULL in case of error.
317 */
318xmlNodeSetPtr
319xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
320 int i;
321
322 if (val1 == NULL) return(NULL);
323 if (val2 == NULL) return(val1);
324
325 /*
326 * !!!!! this can be optimized a lot, knowing that both
327 * val1 and val2 already have unicity of their values.
328 */
329
330 for (i = 0;i < val2->nodeNr;i++)
331 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
332
333 return(val1);
334}
335
336/**
337 * xmlXPathNodeSetDel:
338 * @cur: the initial node set
339 * @val: an xmlNodePtr
340 *
341 * Removes an xmlNodePtr from an existing NodeSet
342 */
343void
344xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
345 int i;
346
347 if (cur == NULL) return;
348 if (val == NULL) return;
349
350 /*
351 * check against doublons
352 */
353 for (i = 0;i < cur->nodeNr;i++)
354 if (cur->nodeTab[i] == val) break;
355
356 if (i >= cur->nodeNr) {
357#ifdef DEBUG
358 fprintf(xmlXPathDebug,
359 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
360 val->name);
361#endif
362 return;
363 }
364 cur->nodeNr--;
365 for (;i < cur->nodeNr;i++)
366 cur->nodeTab[i] = cur->nodeTab[i + 1];
367 cur->nodeTab[cur->nodeNr] = NULL;
368}
369
370/**
371 * xmlXPathNodeSetRemove:
372 * @cur: the initial node set
373 * @val: the index to remove
374 *
375 * Removes an entry from an existing NodeSet list.
376 */
377void
378xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
379 if (cur == NULL) return;
380 if (val >= cur->nodeNr) return;
381 cur->nodeNr--;
382 for (;val < cur->nodeNr;val++)
383 cur->nodeTab[val] = cur->nodeTab[val + 1];
384 cur->nodeTab[cur->nodeNr] = NULL;
385}
386
387/**
388 * xmlXPathFreeNodeSet:
389 * @obj: the xmlNodeSetPtr to free
390 *
391 * Free the NodeSet compound (not the actual nodes !).
392 */
393void
394xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
395 if (obj == NULL) return;
396 if (obj->nodeTab != NULL) {
397#ifdef DEBUG
398 memset(obj->nodeTab, 0xB , sizeof(xmlNodePtr) * obj->nodeMax);
399#endif
400 free(obj->nodeTab);
401 }
402#ifdef DEBUG
403 memset(obj, 0xB , sizeof(xmlNodeSet));
404#endif
405 free(obj);
406}
407
408#ifdef DEBUG
409/**
410 * xmlXPathDebugNodeSet:
411 * @output: a FILE * for the output
412 * @obj: the xmlNodeSetPtr to free
413 *
414 * Quick display of a NodeSet
415 */
416void
417xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
418 int i;
419
420 if (output == NULL) output = xmlXPathDebug;
421 if (obj == NULL) {
422 fprintf(output, "NodeSet == NULL !\n");
423 return;
424 }
425 if (obj->nodeNr == 0) {
426 fprintf(output, "NodeSet is empty\n");
427 return;
428 }
429 if (obj->nodeTab == NULL) {
430 fprintf(output, " nodeTab == NULL !\n");
431 return;
432 }
433 for (i = 0; i < obj->nodeNr; i++) {
434 if (obj->nodeTab[i] == NULL) {
435 fprintf(output, " NULL !\n");
436 return;
437 }
438 if (obj->nodeTab[i]->name == NULL)
439 fprintf(output, " noname!");
440 else fprintf(output, " %s", obj->nodeTab[i]->name);
441 }
442 fprintf(output, "\n");
443}
444#endif
445
446/************************************************************************
447 * *
448 * Routines to handle Variable *
449 * *
450 * UNIMPLEMENTED CURRENTLY *
451 * *
452 ************************************************************************/
453
454/**
455 * xmlXPathVariablelookup:
456 * @ctxt: the XPath Parser context
457 * @prefix: the variable name namespace if any
458 * @name: the variable name
459 *
460 * Search in the Variable array of the context for the given
461 * variable value.
462 *
463 * UNIMPLEMENTED: always return NULL.
464 *
465 * Returns the value or NULL if not found
466 */
467xmlXPathObjectPtr
468xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
469 const CHAR *prefix, const CHAR *name) {
470 return(NULL);
471}
472
473/************************************************************************
474 * *
475 * Routines to handle Values *
476 * *
477 ************************************************************************/
478
479/* Allocations are terrible, one need to optimize all this !!! */
480
481/**
482 * xmlXPathNewFloat:
483 * @val: the float value
484 *
485 * Create a new xmlXPathObjectPtr of type float and of value @val
486 *
487 * Returns the newly created object.
488 */
489xmlXPathObjectPtr
490xmlXPathNewFloat(float val) {
491 xmlXPathObjectPtr ret;
492
493 ret = (xmlXPathObjectPtr) malloc(sizeof(xmlXPathObject));
494 if (ret == NULL) {
495 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
496 return(NULL);
497 }
498 memset(ret, 0 , sizeof(xmlXPathObject));
499 ret->type = XPATH_NUMBER;
500 ret->floatval = val;
501 return(ret);
502}
503
504/**
505 * xmlXPathNewBoolean:
506 * @val: the boolean value
507 *
508 * Create a new xmlXPathObjectPtr of type boolean and of value @val
509 *
510 * Returns the newly created object.
511 */
512xmlXPathObjectPtr
513xmlXPathNewBoolean(int val) {
514 xmlXPathObjectPtr ret;
515
516 ret = (xmlXPathObjectPtr) malloc(sizeof(xmlXPathObject));
517 if (ret == NULL) {
518 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
519 return(NULL);
520 }
521 memset(ret, 0 , sizeof(xmlXPathObject));
522 ret->type = XPATH_BOOLEAN;
523 ret->boolval = (val != 0);
524 return(ret);
525}
526
527/**
528 * xmlXPathNewMarker:
529 *
530 * Create a new xmlXPathObjectPtr of a special marker type for functions
531 *
532 * Returns the newly created object.
533 */
534xmlXPathObjectPtr
535xmlXPathNewMarker(void) {
536 xmlXPathObjectPtr ret;
537
538 ret = (xmlXPathObjectPtr) malloc(sizeof(xmlXPathObject));
539 if (ret == NULL) {
540 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
541 return(NULL);
542 }
543 memset(ret, 0 , sizeof(xmlXPathObject));
544 ret->type = XPATH_MARKER;
545 return(ret);
546}
547
548/**
549 * xmlXPathNewBoolean:
550 * @val: the CHAR * value
551 *
552 * Create a new xmlXPathObjectPtr of type string and of value @val
553 *
554 * Returns the newly created object.
555 */
556xmlXPathObjectPtr
557xmlXPathNewString(const CHAR *val) {
558 xmlXPathObjectPtr ret;
559
560 ret = (xmlXPathObjectPtr) malloc(sizeof(xmlXPathObject));
561 if (ret == NULL) {
562 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
563 return(NULL);
564 }
565 memset(ret, 0 , sizeof(xmlXPathObject));
566 ret->type = XPATH_STRING;
567 ret->stringval = xmlStrdup(val);
568 return(ret);
569}
570
571/**
572 * xmlXPathNewNodeSet:
573 * @val: the NodePtr value
574 *
575 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
576 * it with the single Node @val
577 *
578 * Returns the newly created object.
579 */
580xmlXPathObjectPtr
581xmlXPathNewNodeSet(xmlNodePtr val) {
582 xmlXPathObjectPtr ret;
583
584 ret = (xmlXPathObjectPtr) malloc(sizeof(xmlXPathObject));
585 if (ret == NULL) {
586 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
587 return(NULL);
588 }
589 memset(ret, 0 , sizeof(xmlXPathObject));
590 ret->type = XPATH_NODESET;
591 ret->nodesetval = xmlXPathNodeSetCreate(val);
592 return(ret);
593}
594
595/**
596 * xmlXPathNewNodeSetList:
597 * @val: an existing NodeSet
598 *
599 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
600 * it with the Nodeset @val
601 *
602 * Returns the newly created object.
603 */
604xmlXPathObjectPtr
605xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
606 xmlXPathObjectPtr ret;
607
608 ret = (xmlXPathObjectPtr) malloc(sizeof(xmlXPathObject));
609 if (ret == NULL) {
610 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
611 return(NULL);
612 }
613 memset(ret, 0 , sizeof(xmlXPathObject));
614 ret->type = XPATH_NODESET;
615 ret->nodesetval = val;
616 return(ret);
617}
618
619/**
620 * xmlXPathFreeObject:
621 * @obj: the object to free
622 *
623 * Free up an xmlXPathObjectPtr object.
624 */
625void
626xmlXPathFreeObject(xmlXPathObjectPtr obj) {
627 if (obj == NULL) return;
628 if (obj->nodesetval != NULL)
629 xmlXPathFreeNodeSet(obj->nodesetval);
630 if (obj->stringval != NULL)
631 free(obj->stringval);
632#ifdef DEBUG
633 memset(obj, 0xB , sizeof(xmlXPathObject));
634#endif
635 free(obj);
636}
637
638/************************************************************************
639 * *
640 * Routines to handle XPath contexts *
641 * *
642 ************************************************************************/
643
644/**
645 * xmlXPathNewContext:
646 * @doc: the XML document
647 * @variables: the variable list
648 * @functions: the function list
649 * @namespaces: the namespace list
650 *
651 * Create a new xmlXPathContext
652 *
653 * Returns the xmlXPathContext just allocated.
654 */
655xmlXPathContextPtr
656xmlXPathNewContext(xmlDocPtr doc, void *variables, void *functions,
657 void *namespaces) {
658 xmlXPathContextPtr ret;
659
660 ret = (xmlXPathContextPtr) malloc(sizeof(xmlXPathContext));
661 if (ret == NULL) {
662 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
663 return(NULL);
664 }
665 memset(ret, 0 , sizeof(xmlXPathContext));
666 ret->doc = doc;
667 ret->variables = variables;
668 ret->functions = functions;
669 ret->namespaces = namespaces;
670 return(ret);
671}
672
673/**
674 * xmlXPathFreeContext:
675 * @ctxt: the context to free
676 *
677 * Free up an xmlXPathContext
678 */
679void
680xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
681#ifdef DEBUG
682 memset(ctxt, 0xB , sizeof(xmlXPathContext));
683#endif
684 free(ctxt);
685}
686
687/************************************************************************
688 * *
689 * Routines to handle XPath parser contexts *
690 * *
691 ************************************************************************/
692
693#define CHECK_CTXT \
694 if (ctxt == NULL) { \
695 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
696 __FILE__, __LINE__); \
697 } \
698
699
700#define CHECK_CONTEXT \
701 if (ctxt == NULL) { \
702 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
703 __FILE__, __LINE__); \
704 } \
705 if (ctxt->doc == NULL) { \
706 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
707 __FILE__, __LINE__); \
708 } \
709 if (ctxt->doc->root == NULL) { \
710 fprintf(xmlXPathDebug, \
711 "%s:%d Internal error: document without root\n", \
712 __FILE__, __LINE__); \
713 } \
714
715
716/**
717 * xmlXPathNewParserContext:
718 * @str: the XPath expression
719 * @ctxt: the XPath context
720 *
721 * Create a new xmlXPathParserContext
722 *
723 * Returns the xmlXPathParserContext just allocated.
724 */
725xmlXPathParserContextPtr
726xmlXPathNewParserContext(const CHAR *str, xmlXPathContextPtr ctxt) {
727 xmlXPathParserContextPtr ret;
728
729 ret = (xmlXPathParserContextPtr) malloc(sizeof(xmlXPathParserContext));
730 if (ret == NULL) {
731 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
732 return(NULL);
733 }
734 memset(ret, 0 , sizeof(xmlXPathParserContext));
735 ret->cur = ret->base = str;
736 ret->context = ctxt;
737
738 /* Allocate the value stack */
739 ret->valueTab = (xmlXPathObjectPtr *)
740 malloc(10 * sizeof(xmlXPathObjectPtr));
741 ret->valueNr = 0;
742 ret->valueMax = 10;
743 ret->value = NULL;
744 return(ret);
745}
746
747/**
748 * xmlXPathFreeParserContext:
749 * @ctxt: the context to free
750 *
751 * Free up an xmlXPathParserContext
752 */
753void
754xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
755 if (ctxt->valueTab != NULL) {
756#ifdef DEBUG
757 memset(ctxt->valueTab, 0xB , 10 * sizeof(xmlXPathObjectPtr));
758#endif
759 free(ctxt->valueTab);
760 }
761#ifdef DEBUG
762 memset(ctxt, 0xB , sizeof(xmlXPathParserContext));
763#endif
764 free(ctxt);
765}
766
767/************************************************************************
768 * *
769 * The implicit core function library *
770 * *
771 ************************************************************************/
772
773/*
774 * TODO: check the semantic for all these operations in case of operands
775 * with different types, Cast function probably need to be provided
776 * to simplify the coding.
777 */
778
779/*
780 * Auto-pop and cast to a number
781 */
782void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
783
784#define CHECK_ARITY(x) \
785 if (nargs != (x)) { \
786 ERROR(XPATH_INVALID_ARITY); \
787 } \
788
789
790#define POP_FLOAT \
791 arg = valuePop(ctxt); \
792 if (arg == NULL) { \
793 ERROR(XPATH_INVALID_OPERAND); \
794 } \
795 if (arg->type != XPATH_NUMBER) { \
796 valuePush(ctxt, arg); \
797 xmlXPathNumberFunction(ctxt, 1); \
798 arg = valuePop(ctxt); \
799 }
800
801/**
802 * xmlXPathEqualValues:
803 * @arg1: first XPath object argument
804 * @arg2: second XPath object argument
805 *
806 * Implement the equal operation on XPath objects content: @arg1 == @arg2
807 *
808 * Returns 0 or 1 depending on the results of the test.
809 * TODO: rewrite using the stack for evaluation
810 */
811int
812xmlXPathEqualValues(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
813 if (arg1 == arg2) {
814#ifdef DEBUG_EXPR
815 fprintf(xmlXPathDebug, "Equal: by pointer\n");
816#endif
817 return(1);
818 }
819 if ((arg1 == NULL) || (arg2 == NULL)) {
820#ifdef DEBUG_EXPR
821 fprintf(xmlXPathDebug, "Equal: arg NULL\n");
822#endif
823 return(0);
824 }
825 if (arg1->type != arg2->type) {
826 /* TODO : see 4.3 Boolean section !!!!!!!!!!! */
827#ifdef DEBUG_EXPR
828 fprintf(xmlXPathDebug, "Equal: distinct types\n");
829#endif
830 return(0);
831 }
832 switch (arg1->type) {
833 case XPATH_UNDEFINED:
834#ifdef DEBUG_EXPR
835 fprintf(xmlXPathDebug, "Equal: undefined\n");
836#endif
837 return(0);
838 case XPATH_NODESET:
839 TODO /* compare nodesets */
840 break;
841 case XPATH_BOOLEAN:
842#ifdef DEBUG_EXPR
843 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
844 arg1->boolval, arg2->boolval);
845#endif
846 return(arg1->boolval == arg2->boolval);
847 case XPATH_NUMBER:
848#ifdef DEBUG_EXPR
849 fprintf(xmlXPathDebug, "Equal: %f number %f \n",
850 arg1->floatval, arg2->floatval);
851#endif
852 return(arg1->floatval == arg2->floatval);
853 case XPATH_STRING:
854#ifdef DEBUG_EXPR
855 fprintf(xmlXPathDebug, "Equal: %s string %s \n",
856 arg1->stringval, arg2->stringval);
857#endif
858 return(!xmlStrcmp(arg1->stringval, arg2->stringval));
859 }
860 return(1);
861}
862
863/**
864 * xmlXPathCompareValues:
865 * @inf: less than (1) or greater than (2)
866 * @strict: is the comparison strict
867 * @arg1: first XPath object argument
868 * @arg2: second XPath object argument
869 *
870 * Implement the compare operation on XPath objects:
871 * @arg1 < @arg2 (1, 1, ...
872 * @arg1 <= @arg2 (1, 0, ...
873 * @arg1 > @arg2 (0, 1, ...
874 * @arg1 >= @arg2 (0, 0, ...
875 *
876 * Returns 0 or 1 depending on the results of the test.
877 */
878int
879xmlXPathCompareValues(int inf, int strict, xmlXPathObjectPtr arg1,
880 xmlXPathObjectPtr arg2) {
881 TODO /* compare */
882 return(0);
883}
884
885/**
886 * xmlXPathValueFlipSign:
887 * @ctxt: the XPath Parser context
888 *
889 * Implement the unary - operation on an XPath object
890 * The numeric operators convert their operands to numbers as if
891 * by calling the number function.
892 */
893void
894xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
895 xmlXPathObjectPtr arg;
896
897 POP_FLOAT
898 arg->floatval = -arg->floatval;
899 valuePush(ctxt, arg);
900}
901
902/**
903 * xmlXPathAddValues:
904 * @ctxt: the XPath Parser context
905 *
906 * Implement the add operation on XPath objects: @arg1 + @arg2
907 * The numeric operators convert their operands to numbers as if
908 * by calling the number function.
909 */
910void
911xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
912 xmlXPathObjectPtr arg;
913 float val;
914
915 POP_FLOAT
916 val = arg->floatval;
917 xmlXPathFreeObject(arg);
918
919 POP_FLOAT
920 arg->floatval += val;
921 valuePush(ctxt, arg);
922}
923
924/**
925 * xmlXPathSubValues:
926 * @ctxt: the XPath Parser context
927 *
928 * Implement the substraction operation on XPath objects: @arg1 - @arg2
929 * The numeric operators convert their operands to numbers as if
930 * by calling the number function.
931 */
932void
933xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
934 xmlXPathObjectPtr arg;
935 float val;
936
937 POP_FLOAT
938 val = arg->floatval;
939 xmlXPathFreeObject(arg);
940
941 POP_FLOAT
942 arg->floatval -= val;
943 valuePush(ctxt, arg);
944}
945
946/**
947 * xmlXPathMultValues:
948 * @ctxt: the XPath Parser context
949 *
950 * Implement the multiply operation on XPath objects: @arg1 * @arg2
951 * The numeric operators convert their operands to numbers as if
952 * by calling the number function.
953 */
954void
955xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
956 xmlXPathObjectPtr arg;
957 float val;
958
959 POP_FLOAT
960 val = arg->floatval;
961 xmlXPathFreeObject(arg);
962
963 POP_FLOAT
964 arg->floatval *= val;
965 valuePush(ctxt, arg);
966}
967
968/**
969 * xmlXPathDivValues:
970 * @ctxt: the XPath Parser context
971 *
972 * Implement the div operation on XPath objects: @arg1 / @arg2
973 * The numeric operators convert their operands to numbers as if
974 * by calling the number function.
975 */
976void
977xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
978 xmlXPathObjectPtr arg;
979 float val;
980
981 POP_FLOAT
982 val = arg->floatval;
983 xmlXPathFreeObject(arg);
984
985 POP_FLOAT
986 arg->floatval /= val;
987 valuePush(ctxt, arg);
988}
989
990/**
991 * xmlXPathModValues:
992 * @ctxt: the XPath Parser context
993 *
994 * Implement the div operation on XPath objects: @arg1 / @arg2
995 * The numeric operators convert their operands to numbers as if
996 * by calling the number function.
997 */
998void
999xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1000 xmlXPathObjectPtr arg;
1001 float val;
1002
1003 POP_FLOAT
1004 val = arg->floatval;
1005 xmlXPathFreeObject(arg);
1006
1007 POP_FLOAT
1008 arg->floatval /= val;
1009 valuePush(ctxt, arg);
1010}
1011
1012/************************************************************************
1013 * *
1014 * The traversal functions *
1015 * *
1016 ************************************************************************/
1017
1018#define AXIS_ANCESTOR 1
1019#define AXIS_ANCESTOR_OR_SELF 2
1020#define AXIS_ATTRIBUTE 3
1021#define AXIS_CHILD 4
1022#define AXIS_DESCENDANT 5
1023#define AXIS_DESCENDANT_OR_SELF 6
1024#define AXIS_FOLLOWING 7
1025#define AXIS_FOLLOWING_SIBLING 8
1026#define AXIS_NAMESPACE 9
1027#define AXIS_PARENT 10
1028#define AXIS_PRECEDING 11
1029#define AXIS_PRECEDING_SIBLING 12
1030#define AXIS_SELF 13
1031
1032/*
1033 * A traversal function enumerates nodes along an axis.
1034 * Initially it must be called with NULL, and it indicates
1035 * termination on the axis by returning NULL.
1036 */
1037typedef xmlNodePtr (*xmlXPathTraversalFunction)
1038 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1039
1040/**
1041 * mlXPathNextSelf:
1042 * @ctxt: the XPath Parser context
1043 * @cur: the current node in the traversal
1044 *
1045 * Traversal function for the "self" direction
1046 * he self axis contains just the context node itself
1047 */
1048xmlNodePtr
1049xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1050 if (cur == NULL)
1051 return(ctxt->context->node);
1052 return(NULL);
1053}
1054
1055/**
1056 * mlXPathNextChild:
1057 * @ctxt: the XPath Parser context
1058 * @cur: the current node in the traversal
1059 *
1060 * Traversal function for the "child" direction
1061 * The child axis contains the children of the context node in document order.
1062 */
1063xmlNodePtr
1064xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1065 if (cur == NULL)
1066 return(ctxt->context->node->childs);
1067 return(cur->next);
1068}
1069
1070/**
1071 * mlXPathNextDescendant:
1072 * @ctxt: the XPath Parser context
1073 * @cur: the current node in the traversal
1074 *
1075 * Traversal function for the "descendant" direction
1076 * the descendant axis contains the descendants of the context node in document
1077 * order; a descendant is a child or a child of a child and so on.
1078 */
1079xmlNodePtr
1080xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1081 if (cur == NULL)
1082 return(ctxt->context->node->childs);
1083
1084 if (cur->childs != NULL) return(cur->childs);
1085 if (cur->next != NULL) return(cur->next);
1086
1087 do {
1088 cur = cur->parent;
1089 if (cur == NULL) return(NULL);
1090 if (cur == ctxt->context->node) return(NULL);
1091 if (cur->next != NULL) {
1092 cur = cur->next;
1093 return(cur);
1094 }
1095 } while (cur != NULL);
1096 return(cur);
1097}
1098
1099/**
1100 * mlXPathNextDescendantOrSelf:
1101 * @ctxt: the XPath Parser context
1102 * @cur: the current node in the traversal
1103 *
1104 * Traversal function for the "descendant-or-self" direction
1105 * the descendant-or-self axis contains the context node and the descendants
1106 * of the context node in document order; thus the context node is the first
1107 * node on the axis, and the first child of the context node is the second node
1108 * on the axis
1109 */
1110xmlNodePtr
1111xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1112 if (cur == NULL)
1113 return(ctxt->context->node);
1114
1115 if (cur->childs != NULL) return(cur->childs);
1116 if (cur->next != NULL) return(cur->next);
1117
1118 do {
1119 cur = cur->parent;
1120 if (cur == NULL) return(NULL);
1121 if (cur == ctxt->context->node) return(NULL);
1122 if (cur->next != NULL) {
1123 cur = cur->next;
1124 return(cur);
1125 }
1126 } while (cur != NULL);
1127 return(cur);
1128}
1129
1130/**
1131 * xmlXPathNextParent:
1132 * @ctxt: the XPath Parser context
1133 * @cur: the current node in the traversal
1134 *
1135 * Traversal function for the "parent" direction
1136 * The parent axis contains the parent of the context node, if there is one.
1137 */
1138xmlNodePtr
1139xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1140 /*
1141 * !!!!!!!!!!!!!
1142 * the parent of an attribute or namespace node is the element
1143 * to which the attribute or namespace node is attached
1144 */
1145 if (cur == NULL)
1146 return(ctxt->context->node->parent);
1147 return(NULL);
1148}
1149
1150/**
1151 * xmlXPathNextAncestor:
1152 * @ctxt: the XPath Parser context
1153 * @cur: the current node in the traversal
1154 *
1155 * Traversal function for the "ancestor" direction
1156 * the ancestor axis contains the ancestors of the context node; the ancestors
1157 * of the context node consist of the parent of context node and the parent's
1158 * parent and so on; the nodes are ordered in reverse document order; thus the
1159 * parent is the first node on the axis, and the parent's parent is the second
1160 * node on the axis
1161 */
1162xmlNodePtr
1163xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1164 /*
1165 * !!!!!!!!!!!!!
1166 * the parent of an attribute or namespace node is the element
1167 * to which the attribute or namespace node is attached
1168 */
1169 if (cur == NULL)
1170 return(ctxt->context->node->parent);
1171 if (cur == ctxt->context->doc->root) return(NULL);
1172 return(cur->parent);
1173}
1174
1175/**
1176 * xmlXPathNextAncestorOrSelf:
1177 * @ctxt: the XPath Parser context
1178 * @cur: the current node in the traversal
1179 *
1180 * Traversal function for the "ancestor-or-self" direction
1181 * he ancestor-or-self axis contains the context node and ancestors of the context
1182 * node in reverse document order; thus the context node is the first node on the
1183 * axis, and the context node's parent the second; parent here is defined the same
1184 * as with the parent axis.
1185 */
1186xmlNodePtr
1187xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1188 /*
1189 * !!!!!!!!!!!!!
1190 * the parent of an attribute or namespace node is the element
1191 * to which the attribute or namespace node is attached
1192 */
1193 if (cur == NULL)
1194 return(ctxt->context->node);
1195 if (cur == ctxt->context->doc->root) return(NULL);
1196 return(cur->parent);
1197}
1198
1199/**
1200 * xmlXPathNextFollowingSibling:
1201 * @ctxt: the XPath Parser context
1202 * @cur: the current node in the traversal
1203 *
1204 * Traversal function for the "following-sibling" direction
1205 * The following-sibling axis contains the following siblings of the context
1206 * node in document order.
1207 */
1208xmlNodePtr
1209xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1210 if (cur == NULL)
1211 return(ctxt->context->node->next);
1212 return(cur->next);
1213}
1214
1215/**
1216 * xmlXPathNextPrecedingSibling:
1217 * @ctxt: the XPath Parser context
1218 * @cur: the current node in the traversal
1219 *
1220 * Traversal function for the "preceding-sibling" direction
1221 * The preceding-sibling axis contains the preceding siblings of the context
1222 * node in reverse document order; the first preceding sibling is first on the
1223 * axis; the sibling preceding that node is the second on the axis and so on.
1224 */
1225xmlNodePtr
1226xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1227 if (cur == NULL)
1228 return(ctxt->context->node->prev);
1229 return(cur->prev);
1230}
1231
1232/**
1233 * xmlXPathNextFollowing:
1234 * @ctxt: the XPath Parser context
1235 * @cur: the current node in the traversal
1236 *
1237 * Traversal function for the "following" direction
1238 * The following axis contains all nodes in the same document as the context
1239 * node that are after the context node in document order, excluding any
1240 * descendants and excluding attribute nodes and namespace nodes; the nodes
1241 * are ordered in document order
1242 */
1243xmlNodePtr
1244xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1245 if (cur == NULL)
1246 return(ctxt->context->node->next);; /* !!!!!!!!! */
1247 if (cur->childs != NULL) return(cur->childs);
1248 if (cur->next != NULL) return(cur->next);
1249
1250 do {
1251 cur = cur->parent;
1252 if (cur == NULL) return(NULL);
1253 if (cur == ctxt->context->doc->root) return(NULL);
1254 if (cur->next != NULL) {
1255 cur = cur->next;
1256 return(cur);
1257 }
1258 } while (cur != NULL);
1259 return(cur);
1260}
1261
1262/**
1263 * xmlXPathNextPreceding:
1264 * @ctxt: the XPath Parser context
1265 * @cur: the current node in the traversal
1266 *
1267 * Traversal function for the "preceding" direction
1268 * the preceding axis contains all nodes in the same document as the context
1269 * node that are before the context node in document order, excluding any
1270 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1271 * ordered in reverse document order
1272 */
1273xmlNodePtr
1274xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1275 if (cur == NULL)
1276 return(ctxt->context->node->prev); /* !!!!!!!!! */
1277 if (cur->last != NULL) return(cur->last);
1278 if (cur->prev != NULL) return(cur->prev);
1279
1280 do {
1281 cur = cur->parent;
1282 if (cur == NULL) return(NULL);
1283 if (cur == ctxt->context->doc->root) return(NULL);
1284 if (cur->prev != NULL) {
1285 cur = cur->prev;
1286 return(cur);
1287 }
1288 } while (cur != NULL);
1289 return(cur);
1290}
1291
1292/**
1293 * xmlXPathNextNamespace:
1294 * @ctxt: the XPath Parser context
1295 * @cur: the current attribute in the traversal
1296 *
1297 * Traversal function for the "namespace" direction
1298 * the namespace axis contains the namespace nodes of the context node;
1299 * the order of nodes on this axis is implementation-defined; the axis will
1300 * be empty unless the context node is an element
1301 */
1302xmlAttrPtr
1303xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1304 TODO /* namespace traversal */
1305 return(NULL);
1306}
1307
1308/**
1309 * xmlXPathNextAttribute:
1310 * @ctxt: the XPath Parser context
1311 * @cur: the current attribute in the traversal
1312 *
1313 * Traversal function for the "attribute" direction
1314 */
1315xmlAttrPtr
1316xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1317 if (cur == NULL)
1318 return(ctxt->context->node->properties);
1319 return(cur->next);
1320}
1321
1322/************************************************************************
1323 * *
1324 * NodeTest Functions *
1325 * *
1326 ************************************************************************/
1327
1328#define NODE_TEST_NONE 0
1329#define NODE_TEST_TYPE 1
1330#define NODE_TEST_PI 2
1331#define NODE_TEST_ALL 3
1332#define NODE_TEST_NS 4
1333#define NODE_TEST_NAME 5
1334
1335#define NODE_TYPE_COMMENT 50
1336#define NODE_TYPE_TEXT 51
1337#define NODE_TYPE_PI 52
1338#define NODE_TYPE_NODE 53
1339
1340#define IS_FUNCTION 200
1341
1342/**
1343 * xmlXPathNodeCollectAndTest:
1344 * @ctxt: the XPath Parser context
1345 * @cur: the current node to test
1346 *
1347 * This is the function implementing a step: based on the current list
1348 * of nodes, it builds up a new list, looking at all nodes under that
1349 * axis and selecting them.
1350 *
1351 * Returns the new NodeSet resulting from the search.
1352 */
1353xmlNodeSetPtr
1354xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
1355 int test, int type, const CHAR *prefix, const CHAR *name) {
1356#ifdef DEBUG_STEP
1357 int n = 0, t = 0;
1358#endif
1359 int i;
1360 xmlNodeSetPtr ret;
1361 xmlXPathTraversalFunction next = NULL;
1362 xmlNodePtr cur = NULL;
1363
1364 if (ctxt->context->nodelist == NULL) {
1365 if (ctxt->context->node == NULL) {
1366 fprintf(xmlXPathDebug,
1367 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1368 __FILE__, __LINE__);
1369 return(NULL);
1370 }
1371 STRANGE
1372 return(NULL);
1373 }
1374#ifdef DEBUG_STEP
1375 fprintf(xmlXPathDebug, "new step : ");
1376#endif
1377 switch (axis) {
1378 case AXIS_ANCESTOR:
1379#ifdef DEBUG_STEP
1380 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1381#endif
1382 next = xmlXPathNextAncestor; break;
1383 case AXIS_ANCESTOR_OR_SELF:
1384#ifdef DEBUG_STEP
1385 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1386#endif
1387 next = xmlXPathNextAncestorOrSelf; break;
1388 case AXIS_ATTRIBUTE:
1389#ifdef DEBUG_STEP
1390 fprintf(xmlXPathDebug, "axis 'attributes' ");
1391#endif
1392 TODO /* attribute axis */
1393 break;
1394 case AXIS_CHILD:
1395#ifdef DEBUG_STEP
1396 fprintf(xmlXPathDebug, "axis 'child' ");
1397#endif
1398 next = xmlXPathNextChild; break;
1399 case AXIS_DESCENDANT:
1400#ifdef DEBUG_STEP
1401 fprintf(xmlXPathDebug, "axis 'descendant' ");
1402#endif
1403 next = xmlXPathNextDescendant; break;
1404 case AXIS_DESCENDANT_OR_SELF:
1405#ifdef DEBUG_STEP
1406 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1407#endif
1408 next = xmlXPathNextDescendantOrSelf; break;
1409 case AXIS_FOLLOWING:
1410#ifdef DEBUG_STEP
1411 fprintf(xmlXPathDebug, "axis 'following' ");
1412#endif
1413 next = xmlXPathNextFollowing; break;
1414 case AXIS_FOLLOWING_SIBLING:
1415#ifdef DEBUG_STEP
1416 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1417#endif
1418 next = xmlXPathNextFollowingSibling; break;
1419 case AXIS_NAMESPACE:
1420#ifdef DEBUG_STEP
1421 fprintf(xmlXPathDebug, "axis 'namespace' ");
1422#endif
1423 TODO /* namespace axis */
1424 break;
1425 case AXIS_PARENT:
1426#ifdef DEBUG_STEP
1427 fprintf(xmlXPathDebug, "axis 'parent' ");
1428#endif
1429 next = xmlXPathNextParent; break;
1430 case AXIS_PRECEDING:
1431#ifdef DEBUG_STEP
1432 fprintf(xmlXPathDebug, "axis 'preceding' ");
1433#endif
1434 next = xmlXPathNextPreceding; break;
1435 case AXIS_PRECEDING_SIBLING:
1436#ifdef DEBUG_STEP
1437 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1438#endif
1439 next = xmlXPathNextPrecedingSibling; break;
1440 case AXIS_SELF:
1441#ifdef DEBUG_STEP
1442 fprintf(xmlXPathDebug, "axis 'self' ");
1443#endif
1444 next = xmlXPathNextSelf; break;
1445 }
1446 if (next == NULL) return(NULL);
1447 ret = xmlXPathNodeSetCreate(NULL);
1448#ifdef DEBUG_STEP
1449 fprintf(xmlXPathDebug, " context contains %d nodes\n",
1450 ctxt->context->nodelist->nodeNr);
1451 switch (test) {
1452 case NODE_TEST_NONE:
1453 fprintf(xmlXPathDebug, " seaching for none !!!\n");
1454 break;
1455 case NODE_TEST_TYPE:
1456 fprintf(xmlXPathDebug, " seaching for type %d\n", type);
1457 break;
1458 case NODE_TEST_PI:
1459 fprintf(xmlXPathDebug, " seaching for PI !!!\n");
1460 TODO /* PI search */
1461 break;
1462 case NODE_TEST_ALL:
1463 fprintf(xmlXPathDebug, " seaching for *\n");
1464 break;
1465 case NODE_TEST_NS:
1466 fprintf(xmlXPathDebug, " seaching for namespace %s\n",
1467 prefix);
1468 break;
1469 case NODE_TEST_NAME:
1470 fprintf(xmlXPathDebug, " seaching for name %s\n", name);
1471 if (prefix != NULL)
1472 fprintf(xmlXPathDebug, " with namespace %s\n",
1473 prefix);
1474 break;
1475 }
1476 fprintf(xmlXPathDebug, "Testing : ");
1477#endif
1478 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
1479 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
1480
1481 cur = NULL;
1482 do {
1483 cur = next(ctxt, cur);
1484 if (cur == NULL) break;
1485#ifdef DEBUG_STEP
1486 t++;
1487 fprintf(xmlXPathDebug, " %s", cur->name);
1488#endif
1489 switch (test) {
1490 case NODE_TEST_NONE:
1491 STRANGE
1492 return(NULL);
1493 case NODE_TEST_TYPE:
1494 if (cur->type == type) {
1495#ifdef DEBUG_STEP
1496 n++;
1497#endif
1498 xmlXPathNodeSetAdd(ret, cur);
1499 }
1500 break;
1501 case NODE_TEST_PI:
1502 TODO /* PI search */
1503 break;
1504 case NODE_TEST_ALL:
1505 if (cur->type == XML_ELEMENT_NODE) {
1506#ifdef DEBUG_STEP
1507 n++;
1508#endif
1509 xmlXPathNodeSetAdd(ret, cur);
1510 }
1511 break;
1512 case NODE_TEST_NS:
1513 TODO /* NS search */
1514 break;
1515 case NODE_TEST_NAME:
1516 if (!xmlStrcmp(name, cur->name) &&
1517 (((prefix == NULL) ||
1518 ((cur->ns != NULL) &&
1519 (!xmlStrcmp(prefix, cur->ns->href)))))) {
1520#ifdef DEBUG_STEP
1521 n++;
1522#endif
1523 xmlXPathNodeSetAdd(ret, cur);
1524 }
1525 break;
1526
1527 }
1528 } while (cur != NULL);
1529 }
1530#ifdef DEBUG_STEP
1531 fprintf(xmlXPathDebug,
1532 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
1533#endif
1534 return(ret);
1535}
1536
1537
1538/************************************************************************
1539 * *
1540 * Implicit tree core function library *
1541 * *
1542 ************************************************************************/
1543
1544/**
1545 * xmlXPathRoot:
1546 * @ctxt: the XPath Parser context
1547 *
1548 * Initialize the context to the root of the document
1549 */
1550void
1551xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
1552 if (ctxt->context->nodelist != NULL)
1553 xmlXPathFreeNodeSet(ctxt->context->nodelist);
1554 ctxt->context->node = ctxt->context->doc->root;
1555 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->doc->root);
1556}
1557
1558/**
1559 * xmlXPathSearchPI:
1560 * @ctxt: the XPath Parser context
1561 *
1562 * Search a processing instruction by name. The name is
1563 * in the object on the stack.
1564 */
1565void
1566xmlXPathSearchPI(xmlXPathParserContextPtr ctxt, int nargs) {
1567 TODO /* Search PI */
1568 CHECK_ARITY(0);
1569 CHECK_TYPE(XPATH_NUMBER)
1570}
1571
1572/************************************************************************
1573 * *
1574 * The explicit core function library *
1575 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
1576 * *
1577 ************************************************************************/
1578
1579
1580/**
1581 * xmlXPathLastFunction:
1582 * @ctxt: the XPath Parser context
1583 *
1584 * Implement the last() XPath function
1585 * The last function returns the number of nodes in the context node list.
1586 */
1587void
1588xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1589 CHECK_ARITY(0);
1590 if ((ctxt->context->nodelist == NULL) ||
1591 (ctxt->context->node == NULL) ||
1592 (ctxt->context->nodelist->nodeNr == 0)) {
1593 valuePush(ctxt, xmlXPathNewFloat((float) 0));
1594 } else {
1595 valuePush(ctxt,
1596 xmlXPathNewFloat((float) ctxt->context->nodelist->nodeNr));
1597 }
1598}
1599
1600/**
1601 * xmlXPathPositionFunction:
1602 * @ctxt: the XPath Parser context
1603 *
1604 * Implement the position() XPath function
1605 * The position function returns the position of the context node in the
1606 * context node list. The first position is 1, and so the last positionr
1607 * will be equal to last().
1608 */
1609void
1610xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1611 int i;
1612
1613 CHECK_ARITY(0);
1614 if ((ctxt->context->nodelist == NULL) ||
1615 (ctxt->context->node == NULL) ||
1616 (ctxt->context->nodelist->nodeNr == 0)) {
1617 valuePush(ctxt, xmlXPathNewFloat((float) 0));
1618 }
1619 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
1620 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
1621 valuePush(ctxt, xmlXPathNewFloat((float) i + 1));
1622 return;
1623 }
1624 }
1625 valuePush(ctxt, xmlXPathNewFloat((float) 0));
1626}
1627
1628/**
1629 * xmlXPathCountFunction:
1630 * @ctxt: the XPath Parser context
1631 *
1632 * Implement the count() XPath function
1633 */
1634void
1635xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1636 xmlXPathObjectPtr cur;
1637
1638 CHECK_ARITY(1);
1639 CHECK_TYPE(XPATH_NODESET);
1640 cur = valuePop(ctxt);
1641
1642 valuePush(ctxt, xmlXPathNewFloat((float) cur->nodesetval->nodeNr));
1643 xmlXPathFreeObject(cur);
1644}
1645
1646/**
1647 * xmlXPathIdFunction:
1648 * @ctxt: the XPath Parser context
1649 *
1650 * Implement the id() XPath function
1651 * The id function selects elements by their unique ID
1652 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
1653 * then the result is the union of the result of applying id to the
1654 * string value of each of the nodes in the argument node-set. When the
1655 * argument to id is of any other type, the argument is converted to a
1656 * string as if by a call to the string function; the string is split
1657 * into a whitespace-separated list of tokens (whitespace is any sequence
1658 * of characters matching the production S); the result is a node-set
1659 * containing the elements in the same document as the context node that
1660 * have a unique ID equal to any of the tokens in the list.
1661 */
1662void
1663xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1664 CHECK_ARITY(1);
1665 TODO /* Write ID/IDREF support in libxml first */
1666}
1667
1668/**
1669 * xmlXPathLocalPartFunction:
1670 * @ctxt: the XPath Parser context
1671 *
1672 * Implement the local-part() XPath function
1673 * The local-part function returns a string containing the local part
1674 * of the name of the node in the argument node-set that is first in
1675 * document order. If the node-set is empty or the first node has no
1676 * name, an empty string is returned. If the argument is omitted it
1677 * defaults to the context node.
1678 */
1679void
1680xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1681 xmlXPathObjectPtr cur;
1682
1683 CHECK_ARITY(1);
1684 CHECK_TYPE(XPATH_NODESET);
1685 cur = valuePop(ctxt);
1686
1687 if (cur->nodesetval->nodeNr == 0) {
1688 valuePush(ctxt, xmlXPathNewString(""));
1689 } else {
1690 int i = 0; /* Should be first in document order !!!!! */
1691 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
1692 }
1693 xmlXPathFreeObject(cur);
1694}
1695
1696/**
1697 * xmlXPathNamespaceFunction:
1698 * @ctxt: the XPath Parser context
1699 *
1700 * Implement the namespace() XPath function
1701 * The namespace function returns a string containing the namespace URI
1702 * of the expanded name of the node in the argument node-set that is
1703 * first in document order. If the node-set is empty, the first node has
1704 * no name, or the expanded name has no namespace URI, an empty string
1705 * is returned. If the argument is omitted it defaults to the context node.
1706 */
1707void
1708xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1709 xmlXPathObjectPtr cur;
1710
1711 CHECK_ARITY(1);
1712 CHECK_TYPE(XPATH_NODESET);
1713 cur = valuePop(ctxt);
1714
1715 if (cur->nodesetval->nodeNr == 0) {
1716 valuePush(ctxt, xmlXPathNewString(""));
1717 } else {
1718 int i = 0; /* Should be first in document order !!!!! */
1719
1720 if (cur->nodesetval->nodeTab[i]->ns == NULL)
1721 valuePush(ctxt, xmlXPathNewString(""));
1722 else
1723 valuePush(ctxt, xmlXPathNewString(
1724 cur->nodesetval->nodeTab[i]->ns->href));
1725 }
1726 xmlXPathFreeObject(cur);
1727}
1728
1729/**
1730 * xmlXPathNameFunction:
1731 * @ctxt: the XPath Parser context
1732 *
1733 * Implement the name() XPath function
1734 * The name function returns a string containing a QName representing
1735 * the name of the node in the argument node-set that is first in documenti
1736 * order. The QName must represent the name with respect to the namespace
1737 * declarations in effect on the node whose name is being represented.
1738 * Typically, this will be the form in which the name occurred in the XML
1739 * source. This need not be the case if there are namespace declarations
1740 * in effect on the node that associate multiple prefixes with the same
1741 * namespace. However, an implementation may include information about
1742 * the original prefix in its representation of nodes; in this case, an
1743 * implementation can ensure that the returned string is always the same
1744 * as the QName used in the XML source. If the argument it omitted it
1745 * defaults to the context node.
1746 * Libxml keep the original prefix so the "real qualified name" used is
1747 * returned.
1748 */
1749void
1750xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1751 xmlXPathObjectPtr cur;
1752
1753 CHECK_ARITY(1);
1754 CHECK_TYPE(XPATH_NODESET);
1755 cur = valuePop(ctxt);
1756
1757 if (cur->nodesetval->nodeNr == 0) {
1758 valuePush(ctxt, xmlXPathNewString(""));
1759 } else {
1760 int i = 0; /* Should be first in document order !!!!! */
1761
1762 if (cur->nodesetval->nodeTab[i]->ns == NULL)
1763 valuePush(ctxt, xmlXPathNewString(
1764 cur->nodesetval->nodeTab[i]->name));
1765
1766 else {
1767 CHAR name[2000];
1768 sprintf(name, "%s:%s", cur->nodesetval->nodeTab[i]->ns->prefix,
1769 cur->nodesetval->nodeTab[i]->name);
1770 valuePush(ctxt, xmlXPathNewString(name));
1771 }
1772 }
1773 xmlXPathFreeObject(cur);
1774}
1775
1776/**
1777 * xmlXPathStringFunction:
1778 * @ctxt: the XPath Parser context
1779 *
1780 * Implement the string() XPath function
1781 * he string function converts an object to a string as follows:
1782 * - A node-set is converted to a string by returning the value of
1783 * the node in the node-set that is first in document order.
1784 * If the node-set is empty, an empty string is returned.
1785 * - A number is converted to a string as follows
1786 * + NaN is converted to the string NaN
1787 * + positive zero is converted to the string 0
1788 * + negative zero is converted to the string 0
1789 * + positive infinity is converted to the string Infinity
1790 * + negative infinity is converted to the string -Infinity
1791 * + if the number is an integer, the number is represented in
1792 * decimal form as a Number with no decimal point and no leading
1793 * zeros, preceded by a minus sign (-) if the number is negative
1794 * + otherwise, the number is represented in decimal form as a
1795 * Number including a decimal point with at least one digit
1796 * before the decimal point and at least one digit after the
1797 * decimal point, preceded by a minus sign (-) if the number
1798 * is negative; there must be no leading zeros before the decimal
1799 * point apart possibly from the one required digit immediatelyi
1800 * before the decimal point; beyond the one required digit
1801 * after the decimal point there must be as many, but only as
1802 * many, more digits as are needed to uniquely distinguish the
1803 * number from all other IEEE 754 numeric values.
1804 * - The boolean false value is converted to the string false.
1805 * The boolean true value is converted to the string true.
1806 */
1807void
1808xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1809 xmlXPathObjectPtr cur;
1810
1811 CHECK_ARITY(1);
1812 cur = valuePop(ctxt);
1813 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
1814 switch (cur->type) {
1815 case XPATH_NODESET:
1816 if (cur->nodesetval->nodeNr == 0) {
1817 valuePush(ctxt, xmlXPathNewString(""));
1818 } else {
1819 CHAR *res;
1820 int i = 0; /* Should be first in document order !!!!! */
1821 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
1822 valuePush(ctxt, xmlXPathNewString(res));
1823 free(res);
1824 }
1825 xmlXPathFreeObject(cur);
1826 return;
1827 case XPATH_STRING:
1828 valuePush(ctxt, cur);
1829 return;
1830 case XPATH_BOOLEAN:
1831 if (cur->boolval) valuePush(ctxt, xmlXPathNewString("true"));
1832 else valuePush(ctxt, xmlXPathNewString("false"));
1833 xmlXPathFreeObject(cur);
1834 return;
1835 case XPATH_NUMBER: {
1836 CHAR buf[100];
1837
1838 /* NAN, infinity, etc .... !!!!!! */
1839 sprintf(buf, "%0g", cur->floatval);
1840 valuePush(ctxt, xmlXPathNewString(buf));
1841 return;
1842 }
1843 }
1844 STRANGE
1845}
1846
1847/**
1848 * xmlXPathStringLengthFunction:
1849 * @ctxt: the XPath Parser context
1850 *
1851 * Implement the string-length() XPath function
1852 * The string-length returns the number of characters in the string
1853 * (see [3.6 Strings]). If the argument is omitted, it defaults to
1854 * the context node converted to a string, in other words the value
1855 * of the context node.
1856 */
1857void
1858xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1859 xmlXPathObjectPtr cur;
1860
1861 if (nargs == 0) {
1862 if (ctxt->context->node == NULL) {
1863 valuePush(ctxt, xmlXPathNewFloat(0));
1864 } else {
1865 CHAR *content;
1866
1867 content = xmlNodeGetContent(ctxt->context->node);
1868 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
1869 free(content);
1870 }
1871 return;
1872 }
1873 CHECK_ARITY(1);
1874 CHECK_TYPE(XPATH_STRING);
1875 cur = valuePop(ctxt);
1876 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
1877 xmlXPathFreeObject(cur);
1878}
1879
1880/**
1881 * xmlXPathConcatFunction:
1882 * @ctxt: the XPath Parser context
1883 *
1884 * Implement the concat() XPath function
1885 * The concat function returns the concatenation of its arguments.
1886 */
1887void
1888xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1889 xmlXPathObjectPtr cur, new;
1890 CHAR *tmp;
1891
1892 if (nargs < 2) {
1893 CHECK_ARITY(2);
1894 }
1895
1896 cur = valuePop(ctxt);
1897 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
1898 xmlXPathFreeObject(cur);
1899 return;
1900 }
1901 nargs--;
1902
1903 while (nargs > 0) {
1904 new = valuePop(ctxt);
1905 if ((new == NULL) || (new->type != XPATH_STRING)) {
1906 xmlXPathFreeObject(new);
1907 xmlXPathFreeObject(cur);
1908 ERROR(XPATH_INVALID_TYPE);
1909 }
1910 tmp = xmlStrcat(new->stringval, cur->stringval);
1911 new->stringval = cur->stringval;
1912 cur->stringval = tmp;
1913
1914 xmlXPathFreeObject(new);
1915 nargs--;
1916 }
1917 valuePush(ctxt, cur);
1918}
1919
1920/**
1921 * xmlXPathContainsFunction:
1922 * @ctxt: the XPath Parser context
1923 *
1924 * Implement the contains() XPath function
1925 * The contains function returns true if the first argument string
1926 * contains the second argument string, and otherwise returns false.
1927 */
1928void
1929xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1930 xmlXPathObjectPtr hay, needle;
1931
1932 CHECK_ARITY(2);
1933 CHECK_TYPE(XPATH_STRING);
1934 needle = valuePop(ctxt);
1935 hay = valuePop(ctxt);
1936 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
1937 xmlXPathFreeObject(hay);
1938 xmlXPathFreeObject(needle);
1939 ERROR(XPATH_INVALID_TYPE);
1940 }
1941 if (xmlStrstr(hay->stringval, needle->stringval))
1942 valuePush(ctxt, xmlXPathNewBoolean(1));
1943 else
1944 valuePush(ctxt, xmlXPathNewBoolean(0));
1945 xmlXPathFreeObject(hay);
1946 xmlXPathFreeObject(needle);
1947}
1948
1949/**
1950 * xmlXPathStartsWithFunction:
1951 * @ctxt: the XPath Parser context
1952 *
1953 * Implement the starts-with() XPath function
1954 * The starts-with function returns true if the first argument string
1955 * starts with the second argument string, and otherwise returns false.
1956 */
1957void
1958xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1959 xmlXPathObjectPtr hay, needle;
1960 int n;
1961
1962 CHECK_ARITY(2);
1963 CHECK_TYPE(XPATH_STRING);
1964 needle = valuePop(ctxt);
1965 hay = valuePop(ctxt);
1966 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
1967 xmlXPathFreeObject(hay);
1968 xmlXPathFreeObject(needle);
1969 ERROR(XPATH_INVALID_TYPE);
1970 }
1971 n = xmlStrlen(needle->stringval);
1972 if (xmlStrncmp(hay->stringval, needle->stringval, n))
1973 valuePush(ctxt, xmlXPathNewBoolean(0));
1974 else
1975 valuePush(ctxt, xmlXPathNewBoolean(1));
1976 xmlXPathFreeObject(hay);
1977 xmlXPathFreeObject(needle);
1978}
1979
1980/**
1981 * xmlXPathSubstringFunction:
1982 * @ctxt: the XPath Parser context
1983 *
1984 * Implement the substring() XPath function
1985 * The substring function returns the substring of the first argument
1986 * starting at the position specified in the second argument with
1987 * length specified in the third argument. For example,
1988 * substring("12345",2,3) returns "234". If the third argument is not
1989 * specified, it returns the substring starting at the position specified
1990 * in the second argument and continuing to the end of the string. For
1991 * example, substring("12345",2) returns "2345". More precisely, each
1992 * character in the string (see [3.6 Strings]) is considered to have a
1993 * numeric position: the position of the first character is 1, the position
1994 * of the second character is 2 and so on. The returned substring contains
1995 * those characters for which the position of the character is greater than
1996 * or equal to the second argument and, if the third argument is specified,
1997 * less than the sum of the second and third arguments; the comparisons
1998 * and addition used for the above follow the standard IEEE 754 rules. Thus:
1999 * - substring("12345", 1.5, 2.6) returns "234"
2000 * - substring("12345", 0, 3) returns "12"
2001 * - substring("12345", 0 div 0, 3) returns ""
2002 * - substring("12345", 1, 0 div 0) returns ""
2003 * - substring("12345", -42, 1 div 0) returns "12345"
2004 * - substring("12345", -1 div 0, 1 div 0) returns ""
2005 */
2006void
2007xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2008 xmlXPathObjectPtr str, start, len;
2009 float le, in;
2010 int i, l;
2011 CHAR *ret;
2012
2013 /*
2014 * Conformance needs to be checked !!!!!
2015 */
2016 if (nargs < 2) {
2017 CHECK_ARITY(2);
2018 }
2019 if (nargs > 3) {
2020 CHECK_ARITY(3);
2021 }
2022 if (nargs == 3) {
2023 CHECK_TYPE(XPATH_NUMBER);
2024 len = valuePop(ctxt);
2025 le = len->floatval;
2026 xmlXPathFreeObject(len);
2027 } else {
2028 le = 2000000000;
2029 }
2030 CHECK_TYPE(XPATH_NUMBER);
2031 start = valuePop(ctxt);
2032 in = start->floatval;
2033 xmlXPathFreeObject(start);
2034 CHECK_TYPE(XPATH_STRING);
2035 str = valuePop(ctxt);
2036 le += in;
2037
2038 /* integer index of the first char */
2039 i = in;
2040 if (((float)i) != in) i++;
2041
2042 /* integer index of the last char */
2043 l = le;
2044 if (((float)l) != le) l++;
2045
2046 /* back to a zero based len */
2047 i--;
2048 l--;
2049
2050 /* check against the string len */
2051 if (l > 1024) {
2052 l = xmlStrlen(str->stringval);
2053 }
2054 if (i < 0) {
2055 i = 0;
2056 }
2057
2058 /* number of chars to copy */
2059 l -= i;
2060
2061 ret = xmlStrsub(str->stringval, i, l);
2062 if (ret == NULL)
2063 valuePush(ctxt, xmlXPathNewString(""));
2064 else
2065 valuePush(ctxt, xmlXPathNewString(ret));
2066 xmlXPathFreeObject(str);
2067}
2068
2069/**
2070 * xmlXPathSubstringBeforeFunction:
2071 * @ctxt: the XPath Parser context
2072 *
2073 * Implement the substring-before() XPath function
2074 * The substring-before function returns the substring of the first
2075 * argument string that precedes the first occurrence of the second
2076 * argument string in the first argument string, or the empty string
2077 * if the first argument string does not contain the second argument
2078 * string. For example, substring-before("1999/04/01","/") returns 1999.
2079 */
2080void
2081xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2082 CHECK_ARITY(2);
2083 TODO /* substring before */
2084}
2085
2086/**
2087 * xmlXPathSubstringAfterFunction:
2088 * @ctxt: the XPath Parser context
2089 *
2090 * Implement the substring-after() XPath function
2091 * The substring-after function returns the substring of the first
2092 * argument string that follows the first occurrence of the second
2093 * argument string in the first argument string, or the empty stringi
2094 * if the first argument string does not contain the second argument
2095 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2096 * and substring-after("1999/04/01","19") returns 99/04/01.
2097 */
2098void
2099xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2100 CHECK_ARITY(2);
2101 TODO /* substring after */
2102}
2103
2104/**
2105 * xmlXPathNormalizeFunction:
2106 * @ctxt: the XPath Parser context
2107 *
2108 * Implement the normalize() XPath function
2109 * The normalize function returns the argument string with white
2110 * space normalized by stripping leading and trailing whitespace
2111 * and replacing sequences of whitespace characters by a single
2112 * space. Whitespace characters are the same allowed by the S production
2113 * in XML. If the argument is omitted, it defaults to the context
2114 * node converted to a string, in other words the value of the context node.
2115 */
2116void
2117xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2118 CHECK_ARITY(1);
2119 TODO /* normalize isn't as boring as translate, but pretty much */
2120}
2121
2122/**
2123 * xmlXPathTranslateFunction:
2124 * @ctxt: the XPath Parser context
2125 *
2126 * Implement the translate() XPath function
2127 * The translate function returns the first argument string with
2128 * occurrences of characters in the second argument string replaced
2129 * by the character at the corresponding position in the third argument
2130 * string. For example, translate("bar","abc","ABC") returns the string
2131 * BAr. If there is a character in the second argument string with no
2132 * character at a corresponding position in the third argument string
2133 * (because the second argument string is longer than the third argument
2134 * string), then occurrences of that character in the first argument
2135 * string are removed. For example, translate("--aaa--","abc-","ABC")
2136 * returns "AAA". If a character occurs more than once in second
2137 * argument string, then the first occurrence determines the replacement
2138 * character. If the third argument string is longer than the second
2139 * argument string, then excess characters are ignored.
2140 */
2141void
2142xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2143 CHECK_ARITY(3);
2144 TODO /* translate is boring, waiting for UTF-8 representation too */
2145}
2146
2147/**
2148 * xmlXPathBooleanFunction:
2149 * @ctxt: the XPath Parser context
2150 *
2151 * Implement the boolean() XPath function
2152 * he boolean function converts its argument to a boolean as follows:
2153 * - a number is true if and only if it is neither positive or
2154 * negative zero nor NaN
2155 * - a node-set is true if and only if it is non-empty
2156 * - a string is true if and only if its length is non-zero
2157 */
2158void
2159xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2160 xmlXPathObjectPtr cur;
2161 int res = 0;
2162
2163 CHECK_ARITY(1);
2164 cur = valuePop(ctxt);
2165 if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
2166 switch (cur->type) {
2167 case XPATH_NODESET:
2168 if ((cur->nodesetval == NULL) ||
2169 (cur->nodesetval->nodeNr == 0)) res = 0;
2170 else
2171 res = 1;
2172 break;
2173 case XPATH_STRING:
2174 if ((cur->stringval == NULL) ||
2175 (cur->stringval[0] == 0)) res = 0;
2176 else
2177 res = 1;
2178 break;
2179 case XPATH_BOOLEAN:
2180 valuePush(ctxt, cur);
2181 return;
2182 case XPATH_NUMBER:
2183 if (cur->floatval) res = 1;
2184 break;
2185 default:
2186 STRANGE
2187 }
2188 xmlXPathFreeObject(cur);
2189 valuePush(ctxt, xmlXPathNewBoolean(res));
2190}
2191
2192/**
2193 * xmlXPathNotFunction:
2194 * @ctxt: the XPath Parser context
2195 *
2196 * Implement the not() XPath function
2197 * The not function returns true if its argument is false,
2198 * and false otherwise.
2199 */
2200void
2201xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2202 CHECK_ARITY(1);
2203 CHECK_TYPE(XPATH_BOOLEAN);
2204 ctxt->value->boolval = ! ctxt->value->boolval;
2205}
2206
2207/**
2208 * xmlXPathTrueFunction:
2209 * @ctxt: the XPath Parser context
2210 *
2211 * Implement the true() XPath function
2212 */
2213void
2214xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2215 CHECK_ARITY(0);
2216 valuePush(ctxt, xmlXPathNewBoolean(1));
2217}
2218
2219/**
2220 * xmlXPathFalseFunction:
2221 * @ctxt: the XPath Parser context
2222 *
2223 * Implement the false() XPath function
2224 */
2225void
2226xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2227 CHECK_ARITY(0);
2228 valuePush(ctxt, xmlXPathNewBoolean(0));
2229}
2230
2231/**
2232 * xmlXPathLangFunction:
2233 * @ctxt: the XPath Parser context
2234 *
2235 * Implement the lang() XPath function
2236 * The lang function returns true or false depending on whether the
2237 * language of the context node as specified by xml:lang attributes
2238 * is the same as or is a sublanguage of the language specified by
2239 * the argument string. The language of the context node is determined
2240 * by the value of the xml:lang attribute on the context node, or, if
2241 * the context node has no xml:lang attribute, by the value of the
2242 * xml:lang attribute on the nearest ancestor of the context node that
2243 * has an xml:lang attribute. If there is no such attribute, then lang
2244 * returns false. If there is such an attribute, then lang returns
2245 * true if the attribute value is equal to the argument ignoring case,
2246 * or if there is some suffix starting with - such that the attribute
2247 * value is equal to the argument ignoring that suffix of the attribute
2248 * value and ignoring case.
2249 */
2250void
2251xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2252 CHECK_ARITY(0);
2253 TODO /* Write down xml:lang support in libxml first */
2254}
2255
2256/**
2257 * xmlXPathNumberFunction:
2258 * @ctxt: the XPath Parser context
2259 *
2260 * Implement the number() XPath function
2261 */
2262void
2263xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2264 xmlXPathObjectPtr cur;
2265 float res;
2266
2267 CHECK_ARITY(1);
2268 cur = valuePop(ctxt);
2269 switch (cur->type) {
2270 case XPATH_NODESET:
2271 valuePush(ctxt, cur);
2272 xmlXPathStringFunction(ctxt, 1);
2273 cur = valuePop(ctxt);
2274 case XPATH_STRING:
2275 res = xmlXPathStringEvalNumber(cur->stringval);
2276 valuePush(ctxt, xmlXPathNewFloat(res));
2277 xmlXPathFreeObject(cur);
2278 return;
2279 case XPATH_BOOLEAN:
2280 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2281 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2282 xmlXPathFreeObject(cur);
2283 return;
2284 case XPATH_NUMBER:
2285 valuePush(ctxt, cur);
2286 return;
2287 }
2288 STRANGE
2289}
2290
2291/**
2292 * xmlXPathSumFunction:
2293 * @ctxt: the XPath Parser context
2294 *
2295 * Implement the sum() XPath function
2296 * The sum function returns the sum of the values of the nodes in
2297 * the argument node-set.
2298 */
2299void
2300xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2301 CHECK_ARITY(1);
2302 TODO /* BUG Sum : don't understand the definition */
2303}
2304
2305/**
2306 * xmlXPathFloorFunction:
2307 * @ctxt: the XPath Parser context
2308 *
2309 * Implement the floor() XPath function
2310 * The floor function returns the largest (closest to positive infinity)
2311 * number that is not greater than the argument and that is an integer.
2312 */
2313void
2314xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2315 CHECK_ARITY(1);
2316 CHECK_TYPE(XPATH_NUMBER);
2317 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
2318 ctxt->value->floatval = (float)((int) ctxt->value->floatval);
2319}
2320
2321/**
2322 * xmlXPathCeilingFunction:
2323 * @ctxt: the XPath Parser context
2324 *
2325 * Implement the ceiling() XPath function
2326 * The ceiling function returns the smallest (closest to negative infinity)
2327 * number that is not less than the argument and that is an integer.
2328 */
2329void
2330xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2331 float f;
2332
2333 CHECK_ARITY(1);
2334 CHECK_TYPE(XPATH_NUMBER);
2335 f = (float)((int) ctxt->value->floatval);
2336 if (f != ctxt->value->floatval)
2337 ctxt->value->floatval = f + 1;
2338}
2339
2340/**
2341 * xmlXPathRoundFunction:
2342 * @ctxt: the XPath Parser context
2343 *
2344 * Implement the round() XPath function
2345 * The round function returns the number that is closest to the
2346 * argument and that is an integer. If there are two such numbers,
2347 * then the one that is even is returned.
2348 */
2349void
2350xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2351 float f;
2352
2353 CHECK_ARITY(1);
2354 CHECK_TYPE(XPATH_NUMBER);
2355 /* round(0.50000001) => 0 !!!!! */
2356 f = (float)((int) ctxt->value->floatval);
2357 if (ctxt->value->floatval < f + 0.5)
2358 ctxt->value->floatval = f;
2359 else if (ctxt->value->floatval == f + 0.5)
2360 ctxt->value->floatval = f; /* !!!! Not following the spec here */
2361 else
2362 ctxt->value->floatval = f + 1;
2363}
2364
2365/************************************************************************
2366 * *
2367 * The Parser *
2368 * *
2369 ************************************************************************/
2370
2371/*
2372 * a couple of forward declarations since we use a recursive call based
2373 * implementation.
2374 */
2375void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
2376void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
2377void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
2378void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
2379
2380/**
2381 * xmlXPathParseNCName:
2382 * @ctxt: the XPath Parser context
2383 *
2384 * parse an XML namespace non qualified name.
2385 *
2386 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2387 *
2388 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2389 * CombiningChar | Extender
2390 *
2391 * Returns the namespace name or NULL
2392 */
2393
2394CHAR *
2395xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
2396 const CHAR *q;
2397 CHAR *ret = NULL;
2398
2399 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
2400 q = NEXT;
2401
2402 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2403 (CUR == '.') || (CUR == '-') ||
2404 (CUR == '_') ||
2405 (IS_COMBINING(CUR)) ||
2406 (IS_EXTENDER(CUR)))
2407 NEXT;
2408
2409 ret = xmlStrndup(q, CUR_PTR - q);
2410
2411 return(ret);
2412}
2413
2414/**
2415 * xmlXPathParseQName:
2416 * @ctxt: the XPath Parser context
2417 * @prefix: a CHAR **
2418 *
2419 * parse an XML qualified name
2420 *
2421 * [NS 5] QName ::= (Prefix ':')? LocalPart
2422 *
2423 * [NS 6] Prefix ::= NCName
2424 *
2425 * [NS 7] LocalPart ::= NCName
2426 *
2427 * Returns the function returns the local part, and prefix is updated
2428 * to get the Prefix if any.
2429 */
2430
2431CHAR *
2432xmlXPathParseQName(xmlXPathParserContextPtr ctxt, CHAR **prefix) {
2433 CHAR *ret = NULL;
2434
2435 *prefix = NULL;
2436 ret = xmlXPathParseNCName(ctxt);
2437 if (CUR == ':') {
2438 *prefix = ret;
2439 NEXT;
2440 ret = xmlXPathParseNCName(ctxt);
2441 }
2442 return(ret);
2443}
2444
2445/**
2446 * xmlXPathStringEvalNumber:
2447 * @str: A string to scan
2448 *
2449 * [30] Number ::= Digits ('.' Digits)?
2450 * | '.' Digits
2451 * [31] Digits ::= [0-9]+
2452 *
2453 * Parse and evaluate a Number in the string
2454 *
2455 * BUG: "1.' is not valid ... James promised correction
2456 * as Digits ('.' Digits?)?
2457 *
2458 * Returns the float value.
2459 */
2460float
2461xmlXPathStringEvalNumber(const CHAR *str) {
2462 const CHAR *cur = str;
2463 float ret = 0.0;
2464 float mult = 1;
2465 int ok = 0;
2466
2467 while (*cur == ' ') cur++;
2468 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
2469 return(NAN);
2470 }
2471 while ((*cur >= '0') && (*cur <= '9')) {
2472 ret = ret * 10 + (*cur - '0');
2473 ok = 1;
2474 cur++;
2475 }
2476 if (*cur == '.') {
2477 cur++;
2478 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
2479 return(NAN);
2480 }
2481 while ((*cur >= '0') && (*cur <= '9')) {
2482 mult /= 10;
2483 ret = ret + (*cur - '0') * mult;
2484 cur++;
2485 }
2486 }
2487 while (*cur == ' ') cur++;
2488 if (*cur != 0) return(NAN);
2489 return(ret);
2490}
2491
2492/**
2493 * xmlXPathEvalNumber:
2494 * @ctxt: the XPath Parser context
2495 *
2496 * [30] Number ::= Digits ('.' Digits)?
2497 * | '.' Digits
2498 * [31] Digits ::= [0-9]+
2499 *
2500 * Parse and evaluate a Number, then push it on the stack
2501 *
2502 * BUG: "1.' is not valid ... James promised correction
2503 * as Digits ('.' Digits?)?
2504 */
2505void
2506xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
2507 float ret = 0.0;
2508 float mult = 1;
2509 int ok = 0;
2510
2511 CHECK_ERROR;
2512 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
2513 ERROR(XPATH_NUMBER_ERROR);
2514 }
2515 while ((CUR >= '0') && (CUR <= '9')) {
2516 ret = ret * 10 + (CUR - '0');
2517 ok = 1;
2518 NEXT;
2519 }
2520 if (CUR == '.') {
2521 NEXT;
2522 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
2523 ERROR(XPATH_NUMBER_ERROR);
2524 }
2525 while ((CUR >= '0') && (CUR <= '9')) {
2526 mult /= 10;
2527 ret = ret + (CUR - '0') * mult;
2528 NEXT;
2529 }
2530 }
2531 valuePush(ctxt, xmlXPathNewFloat(ret));
2532}
2533
2534/**
2535 * xmlXPathEvalLiteral:
2536 * @ctxt: the XPath Parser context
2537 *
2538 * Parse a Literal and push it on the stack.
2539 *
2540 * [29] Literal ::= '"' [^"]* '"'
2541 * | "'" [^']* "'"
2542 *
2543 * TODO: memory allocation could be improved.
2544 */
2545void
2546xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
2547 const CHAR *q;
2548 CHAR *ret = NULL;
2549
2550 if (CUR == '"') {
2551 NEXT;
2552 q = CUR_PTR;
2553 while ((IS_CHAR(CUR)) && (CUR != '"'))
2554 NEXT;
2555 if (!IS_CHAR(CUR)) {
2556 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
2557 } else {
2558 ret = xmlStrndup(q, CUR_PTR - q);
2559 NEXT;
2560 }
2561 } else if (CUR == '\'') {
2562 NEXT;
2563 q = CUR_PTR;
2564 while ((IS_CHAR(CUR)) && (CUR != '\''))
2565 NEXT;
2566 if (!IS_CHAR(CUR)) {
2567 ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
2568 } else {
2569 ret = xmlStrndup(q, CUR_PTR - q);
2570 NEXT;
2571 }
2572 } else {
2573 ERROR(XPATH_START_LITERAL_ERROR);
2574 }
2575 if (ret == NULL) return;
2576 valuePush(ctxt, xmlXPathNewString(ret));
2577 free(ret);
2578}
2579
2580/**
2581 * xmlXPathEvalVariableReference:
2582 * @ctxt: the XPath Parser context
2583 *
2584 * Parse a VariableReference, evaluate it and push it on the stack.
2585 *
2586 * The variable bindings consist of a mapping from variable names
2587 * to variable values. The value of a variable is an object, which
2588 * of any of the types that are possible for the value of an expression,
2589 * and may also be of additional types not specified here.
2590 *
2591 * Early evaluation is possible since:
2592 * The variable bindings [...] used to evaluate a subexpression are
2593 * always the same as those used to evaluate the containing expression.
2594 *
2595 * [36] VariableReference ::= '$' QName
2596 */
2597void
2598xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
2599 CHAR *name;
2600 CHAR *prefix;
2601 xmlXPathObjectPtr value;
2602
2603 if (CUR != '$') {
2604 ERROR(XPATH_VARIABLE_REF_ERROR);
2605 }
2606 name = xmlXPathParseQName(ctxt, &prefix);
2607 if (name == NULL) {
2608 ERROR(XPATH_VARIABLE_REF_ERROR);
2609 }
2610 value = xmlXPathVariablelookup(ctxt, prefix, name);
2611 if (value == NULL) {
2612 ERROR(XPATH_UNDEF_VARIABLE_ERROR);
2613 }
2614 valuePush(ctxt, value);
2615 if (prefix != NULL) free(prefix);
2616 free(name);
2617}
2618
2619
2620/**
2621 * xmlXPathFunctionLookup:
2622 * @ctxt: the XPath Parser context
2623 * @name: a name string
2624 *
2625 * Search for a function of the given name
2626 *
2627 * [35] FunctionName ::= QName - NodeType
2628 *
2629 * TODO: for the moment the list is hardcoded from the spec !!!!
2630 *
2631 * Returns the xmlXPathFunction if found, or NULL otherwise
2632 */
2633xmlXPathFunction
2634xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, CHAR *name) {
2635 switch (name[0]) {
2636 case 'b':
2637 if (!xmlStrcmp(name, "boolean"))
2638 return(xmlXPathBooleanFunction);
2639 break;
2640 case 'c':
2641 if (!xmlStrcmp(name, "ceiling"))
2642 return(xmlXPathCeilingFunction);
2643 if (!xmlStrcmp(name, "count"))
2644 return(xmlXPathCountFunction);
2645 if (!xmlStrcmp(name, "concat"))
2646 return(xmlXPathConcatFunction);
2647 if (!xmlStrcmp(name, "contains"))
2648 return(xmlXPathContainsFunction);
2649 break;
2650 case 'i':
2651 if (!xmlStrcmp(name, "id"))
2652 return(xmlXPathIdFunction);
2653 break;
2654 case 'f':
2655 if (!xmlStrcmp(name, "false"))
2656 return(xmlXPathFalseFunction);
2657 if (!xmlStrcmp(name, "floor"))
2658 return(xmlXPathFloorFunction);
2659 break;
2660 case 'l':
2661 if (!xmlStrcmp(name, "last"))
2662 return(xmlXPathLastFunction);
2663 if (!xmlStrcmp(name, "lang"))
2664 return(xmlXPathLangFunction);
2665 if (!xmlStrcmp(name, "local-part"))
2666 return(xmlXPathLocalPartFunction);
2667 break;
2668 case 'n':
2669 if (!xmlStrcmp(name, "not"))
2670 return(xmlXPathNotFunction);
2671 if (!xmlStrcmp(name, "name"))
2672 return(xmlXPathNameFunction);
2673 if (!xmlStrcmp(name, "namespace"))
2674 return(xmlXPathNamespaceFunction);
2675 if (!xmlStrcmp(name, "normalize"))
2676 return(xmlXPathNormalizeFunction);
2677 if (!xmlStrcmp(name, "number"))
2678 return(xmlXPathNumberFunction);
2679 break;
2680 case 'p':
2681 if (!xmlStrcmp(name, "position"))
2682 return(xmlXPathPositionFunction);
2683 break;
2684 case 'r':
2685 if (!xmlStrcmp(name, "round"))
2686 return(xmlXPathRoundFunction);
2687 break;
2688 case 's':
2689 if (!xmlStrcmp(name, "string"))
2690 return(xmlXPathStringFunction);
2691 if (!xmlStrcmp(name, "string-length"))
2692 return(xmlXPathStringLengthFunction);
2693 if (!xmlStrcmp(name, "starts-with"))
2694 return(xmlXPathStartsWithFunction);
2695 if (!xmlStrcmp(name, "substring"))
2696 return(xmlXPathSubstringFunction);
2697 if (!xmlStrcmp(name, "substring-before"))
2698 return(xmlXPathSubstringBeforeFunction);
2699 if (!xmlStrcmp(name, "substring-after"))
2700 return(xmlXPathSubstringAfterFunction);
2701 if (!xmlStrcmp(name, "sum"))
2702 return(xmlXPathSumFunction);
2703 break;
2704 case 't':
2705 if (!xmlStrcmp(name, "true"))
2706 return(xmlXPathTrueFunction);
2707 if (!xmlStrcmp(name, "translate"))
2708 return(xmlXPathTranslateFunction);
2709 break;
2710 }
2711 return(NULL);
2712}
2713
2714/**
2715 * xmlXPathEvalLocationPathName:
2716 * @ctxt: the XPath Parser context
2717 * @name: a name string
2718 *
2719 * Various names in the beginning of a LocationPath expression
2720 * indicate whether that's an Axis, a node type,
2721 *
2722 * [6] AxisName ::= 'ancestor'
2723 * | 'ancestor-or-self'
2724 * | 'attribute'
2725 * | 'child'
2726 * | 'descendant'
2727 * | 'descendant-or-self'
2728 * | 'following'
2729 * | 'following-sibling'
2730 * | 'namespace'
2731 * | 'parent'
2732 * | 'preceding'
2733 * | 'preceding-sibling'
2734 * | 'self'
2735 * [38] NodeType ::= 'comment'
2736 * | 'text'
2737 * | 'processing-instruction'
2738 * | 'node'
2739 */
2740int
2741xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, CHAR *name) {
2742 switch (name[0]) {
2743 case 'a':
2744 if (!xmlStrcmp(name, "ancestor")) return(AXIS_ANCESTOR);
2745 if (!xmlStrcmp(name, "ancestor-or-self")) return(AXIS_ANCESTOR_OR_SELF);
2746 if (!xmlStrcmp(name, "attribute")) return(AXIS_ATTRIBUTE);
2747 break;
2748 case 'c':
2749 if (!xmlStrcmp(name, "child")) return(AXIS_CHILD);
2750 if (!xmlStrcmp(name, "comment")) return(NODE_TYPE_COMMENT);
2751 break;
2752 case 'd':
2753 if (!xmlStrcmp(name, "descendant")) return(AXIS_DESCENDANT);
2754 if (!xmlStrcmp(name, "descendant-or-self")) return(AXIS_DESCENDANT_OR_SELF);
2755 break;
2756 case 'f':
2757 if (!xmlStrcmp(name, "following")) return(AXIS_FOLLOWING);
2758 if (!xmlStrcmp(name, "following-sibling")) return(AXIS_FOLLOWING_SIBLING);
2759 break;
2760 case 'n':
2761 if (!xmlStrcmp(name, "namespace")) return(AXIS_NAMESPACE);
2762 if (!xmlStrcmp(name, "node")) return(NODE_TYPE_NODE);
2763 break;
2764 case 'p':
2765 if (!xmlStrcmp(name, "parent")) return(AXIS_PARENT);
2766 if (!xmlStrcmp(name, "preceding")) return(AXIS_PRECEDING);
2767 if (!xmlStrcmp(name, "preceding-sibling")) return(AXIS_PRECEDING_SIBLING);
2768 if (!xmlStrcmp(name, "processing-instruction")) return(NODE_TYPE_PI);
2769 break;
2770 case 's':
2771 if (!xmlStrcmp(name, "self")) return(AXIS_SELF);
2772 break;
2773 case 't':
2774 if (!xmlStrcmp(name, "text")) return(NODE_TYPE_TEXT);
2775 break;
2776 }
2777 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
2778 return(0);
2779}
2780
2781/**
2782 * xmlXPathEvalFunctionCall:
2783 * @ctxt: the XPath Parser context
2784 *
2785 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
2786 * [17] Argument ::= Expr
2787 *
2788 * Parse and evaluate a function call, the evaluation of all arguments are
2789 * pushed on the stack
2790 */
2791void
2792xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
2793 CHAR *name;
2794 CHAR *prefix;
2795 xmlXPathFunction func;
2796 int nbargs = 0;
2797
2798 name = xmlXPathParseQName(ctxt, &prefix);
2799 if (name == NULL) {
2800 ERROR(XPATH_EXPR_ERROR);
2801 }
2802 func = xmlXPathIsFunction(ctxt, name);
2803 if (func == NULL) {
2804 ERROR(XPATH_UNKNOWN_FUNC_ERROR);
2805 }
2806#ifdef DEBUG_EXPR
2807 fprintf(xmlXPathDebug, "Calling function %s\n", name);
2808#endif
2809
2810 if (CUR != '(') {
2811 ERROR(XPATH_EXPR_ERROR);
2812 }
2813 NEXT;
2814 valuePush(ctxt, xmlXPathNewMarker());
2815
2816 while (CUR != ')') {
2817 xmlXPathEvalExpr(ctxt);
2818 nbargs++;
2819 if (CUR == ')') break;
2820 if (CUR != ',') {
2821 ERROR(XPATH_EXPR_ERROR);
2822 }
2823 NEXT;
2824 }
2825 NEXT;
2826 func(ctxt, nbargs);
2827}
2828
2829/**
2830 * xmlXPathEvalPrimaryExpr:
2831 * @ctxt: the XPath Parser context
2832 *
2833 * [15] PrimaryExpr ::= VariableReference
2834 * | '(' Expr ')'
2835 * | Literal
2836 * | Number
2837 * | FunctionCall
2838 *
2839 * Parse and evaluate a primary expression, then push the result on the stack
2840 */
2841void
2842xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
2843 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
2844 else if (CUR == '(') {
2845 NEXT;
2846 xmlXPathEvalExpr(ctxt);
2847 if (CUR != ')') {
2848 ERROR(XPATH_EXPR_ERROR);
2849 }
2850 NEXT;
2851 } else if (IS_DIGIT(CUR)) {
2852 xmlXPathEvalNumber(ctxt);
2853 } else if ((CUR == '\'') || (CUR == '"')) {
2854 xmlXPathEvalLiteral(ctxt);
2855 } else {
2856 xmlXPathEvalFunctionCall(ctxt);
2857 }
2858}
2859
2860/**
2861 * xmlXPathEvalFilterExpr:
2862 * @ctxt: the XPath Parser context
2863 *
2864 * [20] FilterExpr ::= PrimaryExpr
2865 * | FilterExpr Predicate
2866 *
2867 * Parse and evaluate a filter expression, then push the result on the stack
2868 * Square brackets are used to filter expressions in the same way that
2869 * they are used in location paths. It is an error if the expression to
2870 * be filtered does not evaluate to a node-set. The context node list
2871 * used for evaluating the expression in square brackets is the node-set
2872 * to be filtered listed in document order.
2873 */
2874
2875void
2876xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
2877 /****
2878 xmlNodeSetPtr oldset = NULL;
2879 xmlXPathObjectPtr arg;
2880 ****/
2881
2882 xmlXPathEvalPrimaryExpr(ctxt);
2883 CHECK_ERROR;
2884
2885 if (CUR != '[') return;
2886
2887 CHECK_TYPE(XPATH_NODESET);
2888
2889 /******
2890 TODO: transition from PathExpr to Expr using paths ...
2891 arg = valuePop(ctxt);
2892 oldset = ctxt->context->nodeset;
2893 ctxt->context->nodeset = arg->nodesetval;
2894 ******/
2895
2896 while (CUR == '[') {
2897 xmlXPathEvalPredicate(ctxt);
2898 }
2899
2900
2901}
2902
2903/**
2904 * xmlXPathEvalPathExpr:
2905 * @ctxt: the XPath Parser context
2906 *
2907 * [19] PathExpr ::= LocationPath
2908 * | FilterExpr
2909 * | FilterExpr '/' RelativeLocationPath
2910 * | FilterExpr '//' RelativeLocationPath
2911 *
2912 * Parse and evaluate a path expression, then push the result on the stack
2913 * The / operator and // operators combine an arbitrary expression
2914 * and a relative location path. It is an error if the expression
2915 * does not evaluate to a node-set.
2916 * The / operator does composition in the same way as when / is
2917 * used in a location path. As in location paths, // is short for
2918 * /descendant-or-self::node()/.
2919 */
2920
2921void
2922xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
2923 xmlNodeSetPtr newset = NULL;
2924
2925 /*
2926 * TODO: FilterExpr => PrimaryExpr => FunctionName is possible too
2927 * so we may have to parse a name here, and depending on whether
2928 * it's a function name or not parse a FilterExpr or a LocationPath
2929 * !!!!!!!!!!!! See NOTE1
2930 */
2931
2932 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
2933 (CUR == '\'') || (CUR == '"')) {
2934 xmlXPathEvalFilterExpr(ctxt);
2935 CHECK_ERROR;
2936 if ((CUR == '/') && (NXT(1) == '/')) {
2937 SKIP(2);
2938 if (ctxt->context->nodelist == NULL) {
2939 STRANGE
2940 xmlXPathRoot(ctxt);
2941 }
2942 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
2943 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
2944 if (ctxt->context->nodelist != NULL)
2945 xmlXPathFreeNodeSet(ctxt->context->nodelist);
2946 ctxt->context->nodelist = newset;
2947 ctxt->context->node = NULL;
2948 xmlXPathEvalRelativeLocationPath(ctxt);
2949 } else if (CUR == '/') {
2950 xmlXPathEvalRelativeLocationPath(ctxt);
2951 }
2952 } else {
2953 xmlXPathEvalLocationPath(ctxt);
2954 }
2955}
2956
2957/**
2958 * xmlXPathEvalUnionExpr:
2959 * @ctxt: the XPath Parser context
2960 *
2961 * [18] UnionExpr ::= PathExpr
2962 * | UnionExpr '|' PathExpr
2963 *
2964 * Parse and evaluate an union expression, then push the result on the stack
2965 */
2966
2967void
2968xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
2969 xmlXPathEvalPathExpr(ctxt);
2970 CHECK_ERROR;
2971 if (CUR == '|') {
2972 xmlNodeSetPtr old = ctxt->context->nodelist;
2973
2974 xmlXPathEvalPathExpr(ctxt);
2975
2976 if (ctxt->context->nodelist == NULL)
2977 ctxt->context->nodelist = old;
2978 else {
2979 ctxt->context->nodelist =
2980 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
2981 xmlXPathFreeNodeSet(old);
2982 }
2983 }
2984}
2985
2986/**
2987 * xmlXPathEvalUnaryExpr:
2988 * @ctxt: the XPath Parser context
2989 *
2990 * [27] UnaryExpr ::= UnionExpr
2991 * | '-' UnaryExpr
2992 *
2993 * Parse and evaluate an unary expression, then push the result on the stack
2994 */
2995
2996void
2997xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
2998 int minus = 0;
2999
3000 if (CUR == '-') {
3001 minus = 1;
3002 NEXT;
3003 }
3004 /* xmlXPathEvalUnionExpr(ctxt); NOTE1 !!! */
3005 xmlXPathEvalPrimaryExpr(ctxt);
3006 CHECK_ERROR;
3007 if (minus) {
3008 xmlXPathValueFlipSign(ctxt);
3009 }
3010}
3011
3012/**
3013 * xmlXPathEvalMultiplicativeExpr:
3014 * @ctxt: the XPath Parser context
3015 *
3016 * [26] MultiplicativeExpr ::= UnaryExpr
3017 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3018 * | MultiplicativeExpr 'div' UnaryExpr
3019 * | MultiplicativeExpr 'mod' UnaryExpr
3020 * [34] MultiplyOperator ::= '*'
3021 *
3022 * Parse and evaluate an Additive expression, then push the result on the stack
3023 */
3024
3025void
3026xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3027 xmlXPathEvalUnaryExpr(ctxt);
3028 CHECK_ERROR;
3029 while ((CUR == '*') ||
3030 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3031 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3032 int op = -1;
3033
3034 if (CUR == '*') {
3035 op = 0;
3036 NEXT;
3037 } else if (CUR == 'd') {
3038 op = 1;
3039 SKIP(3);
3040 } else if (CUR == 'm') {
3041 op = 2;
3042 SKIP(3);
3043 }
3044 xmlXPathEvalUnaryExpr(ctxt);
3045 CHECK_ERROR;
3046 switch (op) {
3047 case 0:
3048 xmlXPathMultValues(ctxt);
3049 break;
3050 case 1:
3051 xmlXPathDivValues(ctxt);
3052 break;
3053 case 2:
3054 xmlXPathModValues(ctxt);
3055 break;
3056 }
3057 }
3058}
3059
3060/**
3061 * xmlXPathEvalAdditiveExpr:
3062 * @ctxt: the XPath Parser context
3063 *
3064 * [25] AdditiveExpr ::= MultiplicativeExpr
3065 * | AdditiveExpr '+' MultiplicativeExpr
3066 * | AdditiveExpr '-' MultiplicativeExpr
3067 *
3068 * Parse and evaluate an Additive expression, then push the result on the stack
3069 */
3070
3071void
3072xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3073 xmlXPathEvalMultiplicativeExpr(ctxt);
3074 CHECK_ERROR;
3075 while ((CUR == '+') || (CUR == '-')) {
3076 int plus;
3077
3078 if (CUR == '+') plus = 1;
3079 else plus = 0;
3080 NEXT;
3081 xmlXPathEvalMultiplicativeExpr(ctxt);
3082 CHECK_ERROR;
3083 if (plus) xmlXPathAddValues(ctxt);
3084 else xmlXPathSubValues(ctxt);
3085 }
3086}
3087
3088/**
3089 * xmlXPathEvalRelationalExpr:
3090 * @ctxt: the XPath Parser context
3091 *
3092 * [24] RelationalExpr ::= AdditiveExpr
3093 * | RelationalExpr '<' AdditiveExpr
3094 * | RelationalExpr '>' AdditiveExpr
3095 * | RelationalExpr '<=' AdditiveExpr
3096 * | RelationalExpr '>=' AdditiveExpr
3097 *
3098 * A <= B > C is allowed ? Answer from James, yes with
3099 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3100 * which is basically what got implemented.
3101 *
3102 * Parse and evaluate a Relational expression, then push the result
3103 * on the stack
3104 */
3105
3106void
3107xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3108 xmlXPathEvalAdditiveExpr(ctxt);
3109 CHECK_ERROR;
3110 while ((CUR == '<') ||
3111 (CUR == '>') ||
3112 ((CUR == '<') && (NXT(1) == '=')) ||
3113 ((CUR == '>') && (NXT(1) == '='))) {
3114 xmlXPathObjectPtr arg1, arg2, res;
3115 int inf, strict, equal;
3116
3117 if (CUR == '<') inf = 1;
3118 else inf = 0;
3119 if (NXT(1) == '=') strict = 0;
3120 else strict = 1;
3121 NEXT;
3122 if (!strict) NEXT;
3123 xmlXPathEvalAdditiveExpr(ctxt);
3124 CHECK_ERROR;
3125 arg2 = valuePop(ctxt);
3126 arg1 = valuePop(ctxt);
3127 equal = xmlXPathCompareValues(inf, strict, arg1, arg2);
3128 res = xmlXPathNewBoolean(equal);
3129 valuePush(ctxt, res);
3130 xmlXPathFreeObject(arg1);
3131 xmlXPathFreeObject(arg2);
3132 }
3133}
3134
3135/**
3136 * xmlXPathEvalEqualityExpr:
3137 * @ctxt: the XPath Parser context
3138 *
3139 * [23] EqualityExpr ::= RelationalExpr
3140 * | EqualityExpr '=' RelationalExpr
3141 * | EqualityExpr '!=' RelationalExpr
3142 *
3143 * A != B != C is allowed ? Answer from James, yes with
3144 * (RelationalExpr = RelationalExpr) = RelationalExpr
3145 * (RelationalExpr != RelationalExpr) != RelationalExpr
3146 * which is basically what got implemented.
3147 *
3148 * Parse and evaluate an Equality expression, then push the result on the stack
3149 *
3150 */
3151void
3152xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3153 xmlXPathEvalRelationalExpr(ctxt);
3154 CHECK_ERROR;
3155 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
3156 xmlXPathObjectPtr arg1, arg2, res;
3157 int eq, equal;
3158
3159 if (CUR == '=') eq = 1;
3160 else eq = 0;
3161 NEXT;
3162 if (!eq) NEXT;
3163 xmlXPathEvalRelationalExpr(ctxt);
3164 CHECK_ERROR;
3165 arg2 = valuePop(ctxt);
3166 arg1 = valuePop(ctxt);
3167 equal = xmlXPathEqualValues(arg1, arg2);
3168 if (eq) res = xmlXPathNewBoolean(equal);
3169 else res = xmlXPathNewBoolean(!equal);
3170 valuePush(ctxt, res);
3171 xmlXPathFreeObject(arg1);
3172 xmlXPathFreeObject(arg2);
3173 }
3174}
3175
3176/**
3177 * xmlXPathEvalAndExpr:
3178 * @ctxt: the XPath Parser context
3179 *
3180 * [22] AndExpr ::= EqualityExpr
3181 * | AndExpr 'and' EqualityExpr
3182 *
3183 * Parse and evaluate an AND expression, then push the result on the stack
3184 *
3185 */
3186void
3187xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3188 xmlXPathEvalEqualityExpr(ctxt);
3189 CHECK_ERROR;
3190 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
3191 xmlXPathObjectPtr arg1, arg2;
3192
3193 SKIP(3);
3194 xmlXPathEvalEqualityExpr(ctxt);
3195 CHECK_ERROR;
3196 arg2 = valuePop(ctxt);
3197 arg1 = valuePop(ctxt);
3198 arg1->boolval &= arg2->boolval;
3199 valuePush(ctxt, arg1);
3200 xmlXPathFreeObject(arg2);
3201 }
3202}
3203
3204/**
3205 * xmlXPathEvalExpr:
3206 * @ctxt: the XPath Parser context
3207 *
3208 * [14] Expr ::= OrExpr
3209 * [21] OrExpr ::= AndExpr
3210 * | OrExpr 'or' AndExpr
3211 *
3212 * Parse and evaluate an expression, then push the result on the stack
3213 *
3214 */
3215void
3216xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3217 xmlXPathEvalAndExpr(ctxt);
3218 CHECK_ERROR;
3219 while ((CUR == 'o') && (NXT(1) == 'r')) {
3220 xmlXPathObjectPtr arg1, arg2;
3221
3222 SKIP(2);
3223 xmlXPathEvalAndExpr(ctxt);
3224 CHECK_ERROR;
3225 arg2 = valuePop(ctxt);
3226 arg1 = valuePop(ctxt);
3227 arg1->boolval |= arg2->boolval;
3228 valuePush(ctxt, arg1);
3229 xmlXPathFreeObject(arg2);
3230 }
3231}
3232
3233/**
3234 * xmlXPathEvaluatePredicateResult:
3235 * @ctxt: the XPath Parser context
3236 * @res: the Predicate Expression evaluation result
3237 * @index: index of the current node in the current list
3238 *
3239 * Evaluate a predicate result for the current node.
3240 * A PredicateExpr is evaluated by evaluating the Expr and converting
3241 * the result to a boolean. If the result is a number, the result will
3242 * be converted to true if the number is equal to the position of the
3243 * context node in the context node list (as returned by the position
3244 * function) and will be converted to false otherwise; if the result
3245 * is not a number, then the result will be converted as if by a call
3246 * to the boolean function.
3247 */
3248int
3249xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
3250 xmlXPathObjectPtr res, int index) {
3251 if (res == NULL) return(0);
3252 switch (res->type) {
3253 case XPATH_BOOLEAN:
3254 return(res->boolval);
3255 case XPATH_NUMBER:
3256 return(res->floatval == index);
3257 case XPATH_NODESET:
3258 return(res->nodesetval->nodeNr != 0);
3259 case XPATH_STRING:
3260 return((res->stringval != NULL) &&
3261 (xmlStrlen(res->stringval) != 0));
3262 default:
3263 STRANGE
3264 }
3265 return(0);
3266}
3267
3268/**
3269 * xmlXPathEvalPredicate:
3270 * @ctxt: the XPath Parser context
3271 *
3272 * [8] Predicate ::= '[' PredicateExpr ']'
3273 * [9] PredicateExpr ::= Expr
3274 *
3275 * Parse and evaluate a predicate for all the elements of the
3276 * current node list. Then refine the list by removing all
3277 * nodes where the predicate is false.
3278 */
3279void
3280xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
3281 const CHAR *cur;
3282 xmlXPathObjectPtr res;
3283 xmlNodeSetPtr newset = NULL;
3284 int i;
3285
3286 if (CUR != '[') {
3287 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3288 }
3289 NEXT;
3290 if ((ctxt->context->nodelist == NULL) ||
3291 (ctxt->context->nodelist->nodeNr == 0)) {
3292 ctxt->context->node = NULL;
3293 xmlXPathEvalExpr(ctxt);
3294 CHECK_ERROR;
3295 res = valuePop(ctxt);
3296 if (res != NULL)
3297 xmlXPathFreeObject(res);
3298 } else {
3299 cur = ctxt->cur;
3300 newset = xmlXPathNodeSetCreate(NULL);
3301 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
3302 ctxt->cur = cur;
3303 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
3304 xmlXPathEvalExpr(ctxt);
3305 CHECK_ERROR;
3306 res = valuePop(ctxt);
3307 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
3308 xmlXPathNodeSetAdd(newset,
3309 ctxt->context->nodelist->nodeTab[i]);
3310 if (res != NULL)
3311 xmlXPathFreeObject(res);
3312 }
3313 if (ctxt->context->nodelist != NULL)
3314 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3315 ctxt->context->nodelist = newset;
3316 ctxt->context->node = NULL;
3317 }
3318 if (CUR != ']') {
3319 ERROR(XPATH_INVALID_PREDICATE_ERROR);
3320 }
3321 NEXT;
3322#ifdef DEBUG_STEP
3323 fprintf(xmlXPathDebug, "After predicate : ");
3324 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3325#endif
3326}
3327
3328/**
3329 * xmlXPathEvalBasis:
3330 * @ctxt: the XPath Parser context
3331 *
3332 * [5] Basis ::= AxisName '::' NodeTest
3333 * | AbbreviatedBasis
3334 * [13] AbbreviatedBasis ::= NodeTest
3335 * | '@' NodeTest
3336 * [7] NodeTest ::= WildcardName
3337 * | NodeType '(' ')'
3338 * | 'processing-instruction' '(' Literal ')'
3339 * [37] WildcardName ::= '*'
3340 * | NCName ':' '*'
3341 * | QName
3342 *
3343 * Evaluate one step in a Location Path
3344 */
3345void
3346xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
3347 CHAR *name = NULL;
3348 CHAR *prefix = NULL;
3349 int type = 0;
3350 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
3351 int nodetest = NODE_TEST_NONE;
3352 int nodetype = 0;
3353 xmlNodeSetPtr newset = NULL;
3354
3355 if (CUR == '@') {
3356 TODO /* attributes */
3357 } else if (CUR == '*') {
3358 NEXT;
3359 nodetest = NODE_TEST_ALL;
3360 } else {
3361 name = xmlXPathParseNCName(ctxt);
3362 if (name == NULL) {
3363 ERROR(XPATH_EXPR_ERROR);
3364 }
3365 type = xmlXPathGetNameType(ctxt, name);
3366 switch (type) {
3367 /*
3368 * Simple case: no axis seach all given node types.
3369 */
3370 case NODE_TYPE_COMMENT:
3371 if ((CUR != '(') || (NXT(1) != ')')) break;
3372 SKIP(2);
3373 nodetest = NODE_TEST_TYPE;
3374 nodetype = XML_COMMENT_NODE;
3375 goto search_nodes;
3376 case NODE_TYPE_TEXT:
3377 if ((CUR != '(') || (NXT(1) != ')')) break;
3378 SKIP(2);
3379 nodetest = NODE_TEST_TYPE;
3380 nodetype = XML_TEXT_NODE;
3381 goto search_nodes;
3382 case NODE_TYPE_NODE:
3383 if ((CUR != '(') || (NXT(1) != ')')) {
3384 nodetest = NODE_TEST_NAME;
3385 break;
3386 }
3387 SKIP(2);
3388 nodetest = NODE_TEST_TYPE;
3389 nodetype = XML_ELEMENT_NODE;
3390 goto search_nodes;
3391 case NODE_TYPE_PI:
3392 if (CUR != '(') break;
3393 if (NXT(1) != ')') {
3394 /*
3395 * Specific case: search a PI by name.
3396 */
3397 SKIP(2);
3398 nodetest = NODE_TEST_PI;
3399 xmlXPathEvalLiteral(ctxt);
3400 CHECK_ERROR;
3401 if (CUR != ')')
3402 ERROR(XPATH_UNCLOSED_ERROR);
3403 xmlXPathSearchPI(ctxt, 0);
3404 return;
3405 }
3406 SKIP(2);
3407 nodetest = NODE_TEST_TYPE;
3408 nodetype = XML_PI_NODE;
3409 goto search_nodes;
3410
3411 /*
3412 * Handling of the compund form: got the axis.
3413 */
3414 case AXIS_ANCESTOR:
3415 case AXIS_ANCESTOR_OR_SELF:
3416 case AXIS_ATTRIBUTE:
3417 case AXIS_CHILD:
3418 case AXIS_DESCENDANT:
3419 case AXIS_DESCENDANT_OR_SELF:
3420 case AXIS_FOLLOWING:
3421 case AXIS_FOLLOWING_SIBLING:
3422 case AXIS_NAMESPACE:
3423 case AXIS_PARENT:
3424 case AXIS_PRECEDING:
3425 case AXIS_PRECEDING_SIBLING:
3426 case AXIS_SELF:
3427 if ((CUR != ':') || (NXT(1) != ':')) {
3428 nodetest = NODE_TEST_NAME;
3429 break;
3430 }
3431 SKIP(2);
3432 axis = type;
3433 break;
3434
3435 /*
3436 * Default: abbreviated syntax the axis is AXIS_CHILD
3437 */
3438 default:
3439 nodetest = NODE_TEST_NAME;
3440 }
3441 if (nodetest == NODE_TEST_NONE) {
3442 if (CUR == '*') {
3443 NEXT;
3444 nodetest = NODE_TEST_ALL;
3445 } else {
3446 name = xmlXPathParseQName(ctxt, &prefix);
3447 nodetest = NODE_TEST_NAME;
3448 }
3449 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
3450 NEXT;
3451 prefix = name;
3452 if (CUR == '*') {
3453 NEXT;
3454 nodetest = NODE_TEST_ALL;
3455 } else
3456 name = xmlXPathParseNCName(ctxt);
3457 } else if (name == NULL)
3458 ERROR(XPATH_EXPR_ERROR);
3459 }
3460
3461search_nodes:
3462
3463#ifdef DEBUG_STEP
3464 fprintf(xmlXPathDebug, "Basis : computing new set\n");
3465#endif
3466 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
3467 prefix, name);
3468 if (ctxt->context->nodelist != NULL)
3469 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3470 ctxt->context->nodelist = newset;
3471 ctxt->context->node = NULL;
3472#ifdef DEBUG_STEP
3473 fprintf(xmlXPathDebug, "Basis : ");
3474 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
3475#endif
3476}
3477
3478/**
3479 * xmlXPathEvalStep:
3480 * @ctxt: the XPath Parser context
3481 *
3482 * [4] Step ::= Basis Predicate*
3483 * | AbbreviatedStep
3484 * [12] AbbreviatedStep ::= '.'
3485 * | '..'
3486 *
3487 * Evaluate one step in a Location Path
3488 * A location step of . is short for self::node(). This is
3489 * particularly useful in conjunction with //. For example, the
3490 * location path .//para is short for
3491 * self::node()/descendant-or-self::node()/child::para
3492 * and so will select all para descendant elements of the context
3493 * node.
3494 * Similarly, a location step of .. is short for parent::node().
3495 * For example, ../title is short for parent::node()/child::title
3496 * and so will select the title children of the parent of the context
3497 * node.
3498 */
3499void
3500xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
3501 xmlNodeSetPtr newset = NULL;
3502
3503 if ((CUR == '.') && (NXT(1) == '.')) {
3504 SKIP(2);
3505 if (ctxt->context->nodelist == NULL) {
3506 STRANGE
3507 xmlXPathRoot(ctxt);
3508 }
3509 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
3510 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3511 if (ctxt->context->nodelist != NULL)
3512 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3513 ctxt->context->nodelist = newset;
3514 ctxt->context->node = NULL;
3515 } else if (CUR == '.') {
3516 NEXT;
3517 } else {
3518 xmlXPathEvalBasis(ctxt);
3519 while (CUR == '[') {
3520 xmlXPathEvalPredicate(ctxt);
3521 }
3522 }
3523#ifdef DEBUG_STEP
3524 fprintf(xmlXPathDebug, "Step : ");
3525 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
3526#endif
3527}
3528
3529/**
3530 * xmlXPathEvalRelativeLocationPath:
3531 * @ctxt: the XPath Parser context
3532 *
3533 * [3] RelativeLocationPath ::= Step
3534 * | RelativeLocationPath '/' Step
3535 * | AbbreviatedRelativeLocationPath
3536 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
3537 *
3538 */
3539void
3540xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
3541 xmlNodeSetPtr newset = NULL;
3542
3543 xmlXPathEvalStep(ctxt);
3544 while (CUR == '/') {
3545 if ((CUR == '/') && (NXT(1) == '/')) {
3546 SKIP(2);
3547 if (ctxt->context->nodelist == NULL) {
3548 STRANGE
3549 xmlXPathRoot(ctxt);
3550 }
3551 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3552 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3553 if (ctxt->context->nodelist != NULL)
3554 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3555 ctxt->context->nodelist = newset;
3556 ctxt->context->node = NULL;
3557 xmlXPathEvalStep(ctxt);
3558 } else if (CUR == '/') {
3559 NEXT;
3560 xmlXPathEvalStep(ctxt);
3561 }
3562 }
3563}
3564
3565/**
3566 * xmlXPathEvalLocationPath:
3567 * @ctxt: the XPath Parser context
3568 *
3569 * [1] LocationPath ::= RelativeLocationPath
3570 * | AbsoluteLocationPath
3571 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
3572 * | AbbreviatedAbsoluteLocationPath
3573 * [10] AbbreviatedAbsoluteLocationPath ::=
3574 * '//' RelativeLocationPath
3575 *
3576 * // is short for /descendant-or-self::node()/. For example,
3577 * //para is short for /descendant-or-self::node()/child::para and
3578 * so will select any para element in the document (even a para element
3579 * that is a document element will be selected by //para since the
3580 * document element node is a child of the root node); div//para is
3581 * short for div/descendant-or-self::node()/child::para and so will
3582 * select all para descendants of div children.
3583 */
3584void
3585xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
3586 xmlNodeSetPtr newset = NULL;
3587
3588 while (CUR == '/') {
3589 if ((CUR == '/') && (NXT(1) == '/')) {
3590 SKIP(2);
3591 if (ctxt->context->nodelist == NULL)
3592 xmlXPathRoot(ctxt);
3593 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3594 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3595 if (ctxt->context->nodelist != NULL)
3596 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3597 ctxt->context->nodelist = newset;
3598 ctxt->context->node = NULL;
3599 xmlXPathEvalRelativeLocationPath(ctxt);
3600 } else if (CUR == '/') {
3601 NEXT;
3602 xmlXPathRoot(ctxt);
3603 xmlXPathEvalRelativeLocationPath(ctxt);
3604 } else {
3605 xmlXPathEvalRelativeLocationPath(ctxt);
3606 }
3607 }
3608}
3609
3610/*
3611 * TODO * extra spaces *
3612 * more tokenization rules ... Not used currently, especially allowing
3613 * spaces before and after ExprToken !!!!!!!!!!!!!
3614 *
3615 * [32] Operator ::= OperatorName
3616 * | MultiplyOperator
3617 * | '/' | '//' | '|' | '+' | '-' | '=' | '!='
3618 * | '<'| '<=' | '>' | '>='
3619 * [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
3620 * [39] ExprWhitespace ::= S
3621 *
3622 * BUG: ExprToken is never referenced.
3623 *
3624 * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
3625 * | WildcardName
3626 * | NodeType
3627 * | Operator
3628 * | FunctionName
3629 * | AxisName
3630 * | Literal
3631 * | Number
3632 * | VariableReference
3633 */
3634
3635/**
3636 * xmlXPathEval:
3637 * @str: the XPath expression
3638 * @ctxt: the XPath context
3639 *
3640 * Evaluate the XPath Location Path in the given context.
3641 *
3642 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
3643 * the caller has to free the object.
3644 */
3645xmlXPathObjectPtr
3646xmlXPathEval(const CHAR *str, xmlXPathContextPtr ctxt) {
3647 xmlXPathParserContextPtr pctxt;
3648 xmlXPathObjectPtr res;
3649
3650 CHECK_CONTEXT
3651
3652 if (xmlXPathDebug == NULL)
3653 xmlXPathDebug = stderr;
3654 pctxt = xmlXPathNewParserContext(str, ctxt);
3655 xmlXPathEvalLocationPath(pctxt);
3656
3657 do {
3658 res = valuePop(pctxt);
3659#ifdef DEBUG
3660#endif
3661 } while (res != NULL);
3662 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
3663 xmlXPathFreeParserContext(pctxt);
3664 return(res);
3665}
3666
3667/**
3668 * xmlXPathEvalExpression:
3669 * @str: the XPath expression
3670 * @ctxt: the XPath context
3671 *
3672 * Evaluate the XPath expression in the given context.
3673 *
3674 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
3675 * the caller has to free the object.
3676 */
3677xmlXPathObjectPtr
3678xmlXPathEvalExpression(const CHAR *str, xmlXPathContextPtr ctxt) {
3679 xmlXPathParserContextPtr pctxt;
3680 xmlXPathObjectPtr res, tmp;
3681
3682 CHECK_CONTEXT
3683
3684 if (xmlXPathDebug == NULL)
3685 xmlXPathDebug = stderr;
3686 pctxt = xmlXPathNewParserContext(str, ctxt);
3687 xmlXPathEvalExpr(pctxt);
3688
3689 res = valuePop(pctxt);
3690 do {
3691 tmp = valuePop(pctxt);
3692#ifdef DEBUG
3693#endif
3694 } while (tmp != NULL);
3695 xmlXPathFreeParserContext(pctxt);
3696 return(res);
3697}
3698