Annotation of embedaddon/libxml2/xpointer.c, revision 1.1.1.1
1.1 misho 1: /*
2: * xpointer.c : Code to handle XML Pointer
3: *
4: * Base implementation was made accordingly to
5: * W3C Candidate Recommendation 7 June 2000
6: * http://www.w3.org/TR/2000/CR-xptr-20000607
7: *
8: * Added support for the element() scheme described in:
9: * W3C Proposed Recommendation 13 November 2002
10: * http://www.w3.org/TR/2002/PR-xptr-element-20021113/
11: *
12: * See Copyright for the status of this software.
13: *
14: * daniel@veillard.com
15: */
16:
17: #define IN_LIBXML
18: #include "libxml.h"
19:
20: /*
21: * TODO: better handling of error cases, the full expression should
22: * be parsed beforehand instead of a progressive evaluation
23: * TODO: Access into entities references are not supported now ...
24: * need a start to be able to pop out of entities refs since
25: * parent is the endity declaration, not the ref.
26: */
27:
28: #include <string.h>
29: #include <libxml/xpointer.h>
30: #include <libxml/xmlmemory.h>
31: #include <libxml/parserInternals.h>
32: #include <libxml/uri.h>
33: #include <libxml/xpath.h>
34: #include <libxml/xpathInternals.h>
35: #include <libxml/xmlerror.h>
36: #include <libxml/globals.h>
37:
38: #ifdef LIBXML_XPTR_ENABLED
39:
40: /* Add support of the xmlns() xpointer scheme to initialize the namespaces */
41: #define XPTR_XMLNS_SCHEME
42:
43: /* #define DEBUG_RANGES */
44: #ifdef DEBUG_RANGES
45: #ifdef LIBXML_DEBUG_ENABLED
46: #include <libxml/debugXML.h>
47: #endif
48: #endif
49:
50: #define TODO \
51: xmlGenericError(xmlGenericErrorContext, \
52: "Unimplemented block at %s:%d\n", \
53: __FILE__, __LINE__);
54:
55: #define STRANGE \
56: xmlGenericError(xmlGenericErrorContext, \
57: "Internal error at %s:%d\n", \
58: __FILE__, __LINE__);
59:
60: /************************************************************************
61: * *
62: * Some factorized error routines *
63: * *
64: ************************************************************************/
65:
66: /**
67: * xmlXPtrErrMemory:
68: * @extra: extra informations
69: *
70: * Handle a redefinition of attribute error
71: */
72: static void
73: xmlXPtrErrMemory(const char *extra)
74: {
75: __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER,
76: XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
77: NULL, NULL, 0, 0,
78: "Memory allocation failed : %s\n", extra);
79: }
80:
81: /**
82: * xmlXPtrErr:
83: * @ctxt: an XPTR evaluation context
84: * @extra: extra informations
85: *
86: * Handle a redefinition of attribute error
87: */
88: static void
89: xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error,
90: const char * msg, const xmlChar *extra)
91: {
92: if (ctxt != NULL)
93: ctxt->error = error;
94: if ((ctxt == NULL) || (ctxt->context == NULL)) {
95: __xmlRaiseError(NULL, NULL, NULL,
96: NULL, NULL, XML_FROM_XPOINTER, error,
97: XML_ERR_ERROR, NULL, 0,
98: (const char *) extra, NULL, NULL, 0, 0,
99: msg, extra);
100: return;
101: }
102: ctxt->context->lastError.domain = XML_FROM_XPOINTER;
103: ctxt->context->lastError.code = error;
104: ctxt->context->lastError.level = XML_ERR_ERROR;
105: ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
106: ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
107: ctxt->context->lastError.node = ctxt->context->debugNode;
108: if (ctxt->context->error != NULL) {
109: ctxt->context->error(ctxt->context->userData,
110: &ctxt->context->lastError);
111: } else {
112: __xmlRaiseError(NULL, NULL, NULL,
113: NULL, ctxt->context->debugNode, XML_FROM_XPOINTER,
114: error, XML_ERR_ERROR, NULL, 0,
115: (const char *) extra, (const char *) ctxt->base, NULL,
116: ctxt->cur - ctxt->base, 0,
117: msg, extra);
118: }
119: }
120:
121: /************************************************************************
122: * *
123: * A few helper functions for child sequences *
124: * *
125: ************************************************************************/
126: /* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */
127: xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level);
128: /**
129: * xmlXPtrGetArity:
130: * @cur: the node
131: *
132: * Returns the number of child for an element, -1 in case of error
133: */
134: static int
135: xmlXPtrGetArity(xmlNodePtr cur) {
136: int i;
137: if (cur == NULL)
138: return(-1);
139: cur = cur->children;
140: for (i = 0;cur != NULL;cur = cur->next) {
141: if ((cur->type == XML_ELEMENT_NODE) ||
142: (cur->type == XML_DOCUMENT_NODE) ||
143: (cur->type == XML_HTML_DOCUMENT_NODE)) {
144: i++;
145: }
146: }
147: return(i);
148: }
149:
150: /**
151: * xmlXPtrGetIndex:
152: * @cur: the node
153: *
154: * Returns the index of the node in its parent children list, -1
155: * in case of error
156: */
157: static int
158: xmlXPtrGetIndex(xmlNodePtr cur) {
159: int i;
160: if (cur == NULL)
161: return(-1);
162: for (i = 1;cur != NULL;cur = cur->prev) {
163: if ((cur->type == XML_ELEMENT_NODE) ||
164: (cur->type == XML_DOCUMENT_NODE) ||
165: (cur->type == XML_HTML_DOCUMENT_NODE)) {
166: i++;
167: }
168: }
169: return(i);
170: }
171:
172: /**
173: * xmlXPtrGetNthChild:
174: * @cur: the node
175: * @no: the child number
176: *
177: * Returns the @no'th element child of @cur or NULL
178: */
179: static xmlNodePtr
180: xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
181: int i;
182: if (cur == NULL)
183: return(cur);
184: cur = cur->children;
185: for (i = 0;i <= no;cur = cur->next) {
186: if (cur == NULL)
187: return(cur);
188: if ((cur->type == XML_ELEMENT_NODE) ||
189: (cur->type == XML_DOCUMENT_NODE) ||
190: (cur->type == XML_HTML_DOCUMENT_NODE)) {
191: i++;
192: if (i == no)
193: break;
194: }
195: }
196: return(cur);
197: }
198:
199: /************************************************************************
200: * *
201: * Handling of XPointer specific types *
202: * *
203: ************************************************************************/
204:
205: /**
206: * xmlXPtrCmpPoints:
207: * @node1: the first node
208: * @index1: the first index
209: * @node2: the second node
210: * @index2: the second index
211: *
212: * Compare two points w.r.t document order
213: *
214: * Returns -2 in case of error 1 if first point < second point, 0 if
215: * that's the same point, -1 otherwise
216: */
217: static int
218: xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) {
219: if ((node1 == NULL) || (node2 == NULL))
220: return(-2);
221: /*
222: * a couple of optimizations which will avoid computations in most cases
223: */
224: if (node1 == node2) {
225: if (index1 < index2)
226: return(1);
227: if (index1 > index2)
228: return(-1);
229: return(0);
230: }
231: return(xmlXPathCmpNodes(node1, node2));
232: }
233:
234: /**
235: * xmlXPtrNewPoint:
236: * @node: the xmlNodePtr
237: * @indx: the indx within the node
238: *
239: * Create a new xmlXPathObjectPtr of type point
240: *
241: * Returns the newly created object.
242: */
243: static xmlXPathObjectPtr
244: xmlXPtrNewPoint(xmlNodePtr node, int indx) {
245: xmlXPathObjectPtr ret;
246:
247: if (node == NULL)
248: return(NULL);
249: if (indx < 0)
250: return(NULL);
251:
252: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
253: if (ret == NULL) {
254: xmlXPtrErrMemory("allocating point");
255: return(NULL);
256: }
257: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
258: ret->type = XPATH_POINT;
259: ret->user = (void *) node;
260: ret->index = indx;
261: return(ret);
262: }
263:
264: /**
265: * xmlXPtrRangeCheckOrder:
266: * @range: an object range
267: *
268: * Make sure the points in the range are in the right order
269: */
270: static void
271: xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) {
272: int tmp;
273: xmlNodePtr tmp2;
274: if (range == NULL)
275: return;
276: if (range->type != XPATH_RANGE)
277: return;
278: if (range->user2 == NULL)
279: return;
280: tmp = xmlXPtrCmpPoints(range->user, range->index,
281: range->user2, range->index2);
282: if (tmp == -1) {
283: tmp2 = range->user;
284: range->user = range->user2;
285: range->user2 = tmp2;
286: tmp = range->index;
287: range->index = range->index2;
288: range->index2 = tmp;
289: }
290: }
291:
292: /**
293: * xmlXPtrRangesEqual:
294: * @range1: the first range
295: * @range2: the second range
296: *
297: * Compare two ranges
298: *
299: * Returns 1 if equal, 0 otherwise
300: */
301: static int
302: xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
303: if (range1 == range2)
304: return(1);
305: if ((range1 == NULL) || (range2 == NULL))
306: return(0);
307: if (range1->type != range2->type)
308: return(0);
309: if (range1->type != XPATH_RANGE)
310: return(0);
311: if (range1->user != range2->user)
312: return(0);
313: if (range1->index != range2->index)
314: return(0);
315: if (range1->user2 != range2->user2)
316: return(0);
317: if (range1->index2 != range2->index2)
318: return(0);
319: return(1);
320: }
321:
322: /**
323: * xmlXPtrNewRange:
324: * @start: the starting node
325: * @startindex: the start index
326: * @end: the ending point
327: * @endindex: the ending index
328: *
329: * Create a new xmlXPathObjectPtr of type range
330: *
331: * Returns the newly created object.
332: */
333: xmlXPathObjectPtr
334: xmlXPtrNewRange(xmlNodePtr start, int startindex,
335: xmlNodePtr end, int endindex) {
336: xmlXPathObjectPtr ret;
337:
338: if (start == NULL)
339: return(NULL);
340: if (end == NULL)
341: return(NULL);
342: if (startindex < 0)
343: return(NULL);
344: if (endindex < 0)
345: return(NULL);
346:
347: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
348: if (ret == NULL) {
349: xmlXPtrErrMemory("allocating range");
350: return(NULL);
351: }
352: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
353: ret->type = XPATH_RANGE;
354: ret->user = start;
355: ret->index = startindex;
356: ret->user2 = end;
357: ret->index2 = endindex;
358: xmlXPtrRangeCheckOrder(ret);
359: return(ret);
360: }
361:
362: /**
363: * xmlXPtrNewRangePoints:
364: * @start: the starting point
365: * @end: the ending point
366: *
367: * Create a new xmlXPathObjectPtr of type range using 2 Points
368: *
369: * Returns the newly created object.
370: */
371: xmlXPathObjectPtr
372: xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
373: xmlXPathObjectPtr ret;
374:
375: if (start == NULL)
376: return(NULL);
377: if (end == NULL)
378: return(NULL);
379: if (start->type != XPATH_POINT)
380: return(NULL);
381: if (end->type != XPATH_POINT)
382: return(NULL);
383:
384: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
385: if (ret == NULL) {
386: xmlXPtrErrMemory("allocating range");
387: return(NULL);
388: }
389: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
390: ret->type = XPATH_RANGE;
391: ret->user = start->user;
392: ret->index = start->index;
393: ret->user2 = end->user;
394: ret->index2 = end->index;
395: xmlXPtrRangeCheckOrder(ret);
396: return(ret);
397: }
398:
399: /**
400: * xmlXPtrNewRangePointNode:
401: * @start: the starting point
402: * @end: the ending node
403: *
404: * Create a new xmlXPathObjectPtr of type range from a point to a node
405: *
406: * Returns the newly created object.
407: */
408: xmlXPathObjectPtr
409: xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
410: xmlXPathObjectPtr ret;
411:
412: if (start == NULL)
413: return(NULL);
414: if (end == NULL)
415: return(NULL);
416: if (start->type != XPATH_POINT)
417: return(NULL);
418:
419: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
420: if (ret == NULL) {
421: xmlXPtrErrMemory("allocating range");
422: return(NULL);
423: }
424: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
425: ret->type = XPATH_RANGE;
426: ret->user = start->user;
427: ret->index = start->index;
428: ret->user2 = end;
429: ret->index2 = -1;
430: xmlXPtrRangeCheckOrder(ret);
431: return(ret);
432: }
433:
434: /**
435: * xmlXPtrNewRangeNodePoint:
436: * @start: the starting node
437: * @end: the ending point
438: *
439: * Create a new xmlXPathObjectPtr of type range from a node to a point
440: *
441: * Returns the newly created object.
442: */
443: xmlXPathObjectPtr
444: xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
445: xmlXPathObjectPtr ret;
446:
447: if (start == NULL)
448: return(NULL);
449: if (end == NULL)
450: return(NULL);
451: if (start->type != XPATH_POINT)
452: return(NULL);
453: if (end->type != XPATH_POINT)
454: return(NULL);
455:
456: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
457: if (ret == NULL) {
458: xmlXPtrErrMemory("allocating range");
459: return(NULL);
460: }
461: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
462: ret->type = XPATH_RANGE;
463: ret->user = start;
464: ret->index = -1;
465: ret->user2 = end->user;
466: ret->index2 = end->index;
467: xmlXPtrRangeCheckOrder(ret);
468: return(ret);
469: }
470:
471: /**
472: * xmlXPtrNewRangeNodes:
473: * @start: the starting node
474: * @end: the ending node
475: *
476: * Create a new xmlXPathObjectPtr of type range using 2 nodes
477: *
478: * Returns the newly created object.
479: */
480: xmlXPathObjectPtr
481: xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
482: xmlXPathObjectPtr ret;
483:
484: if (start == NULL)
485: return(NULL);
486: if (end == NULL)
487: return(NULL);
488:
489: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
490: if (ret == NULL) {
491: xmlXPtrErrMemory("allocating range");
492: return(NULL);
493: }
494: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
495: ret->type = XPATH_RANGE;
496: ret->user = start;
497: ret->index = -1;
498: ret->user2 = end;
499: ret->index2 = -1;
500: xmlXPtrRangeCheckOrder(ret);
501: return(ret);
502: }
503:
504: /**
505: * xmlXPtrNewCollapsedRange:
506: * @start: the starting and ending node
507: *
508: * Create a new xmlXPathObjectPtr of type range using a single nodes
509: *
510: * Returns the newly created object.
511: */
512: xmlXPathObjectPtr
513: xmlXPtrNewCollapsedRange(xmlNodePtr start) {
514: xmlXPathObjectPtr ret;
515:
516: if (start == NULL)
517: return(NULL);
518:
519: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
520: if (ret == NULL) {
521: xmlXPtrErrMemory("allocating range");
522: return(NULL);
523: }
524: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
525: ret->type = XPATH_RANGE;
526: ret->user = start;
527: ret->index = -1;
528: ret->user2 = NULL;
529: ret->index2 = -1;
530: return(ret);
531: }
532:
533: /**
534: * xmlXPtrNewRangeNodeObject:
535: * @start: the starting node
536: * @end: the ending object
537: *
538: * Create a new xmlXPathObjectPtr of type range from a not to an object
539: *
540: * Returns the newly created object.
541: */
542: xmlXPathObjectPtr
543: xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
544: xmlXPathObjectPtr ret;
545:
546: if (start == NULL)
547: return(NULL);
548: if (end == NULL)
549: return(NULL);
550: switch (end->type) {
551: case XPATH_POINT:
552: case XPATH_RANGE:
553: break;
554: case XPATH_NODESET:
555: /*
556: * Empty set ...
557: */
558: if (end->nodesetval->nodeNr <= 0)
559: return(NULL);
560: break;
561: default:
562: /* TODO */
563: return(NULL);
564: }
565:
566: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
567: if (ret == NULL) {
568: xmlXPtrErrMemory("allocating range");
569: return(NULL);
570: }
571: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
572: ret->type = XPATH_RANGE;
573: ret->user = start;
574: ret->index = -1;
575: switch (end->type) {
576: case XPATH_POINT:
577: ret->user2 = end->user;
578: ret->index2 = end->index;
579: break;
580: case XPATH_RANGE:
581: ret->user2 = end->user2;
582: ret->index2 = end->index2;
583: break;
584: case XPATH_NODESET: {
585: ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
586: ret->index2 = -1;
587: break;
588: }
589: default:
590: STRANGE
591: return(NULL);
592: }
593: xmlXPtrRangeCheckOrder(ret);
594: return(ret);
595: }
596:
597: #define XML_RANGESET_DEFAULT 10
598:
599: /**
600: * xmlXPtrLocationSetCreate:
601: * @val: an initial xmlXPathObjectPtr, or NULL
602: *
603: * Create a new xmlLocationSetPtr of type double and of value @val
604: *
605: * Returns the newly created object.
606: */
607: xmlLocationSetPtr
608: xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) {
609: xmlLocationSetPtr ret;
610:
611: ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet));
612: if (ret == NULL) {
613: xmlXPtrErrMemory("allocating locationset");
614: return(NULL);
615: }
616: memset(ret, 0 , (size_t) sizeof(xmlLocationSet));
617: if (val != NULL) {
618: ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
619: sizeof(xmlXPathObjectPtr));
620: if (ret->locTab == NULL) {
621: xmlXPtrErrMemory("allocating locationset");
622: xmlFree(ret);
623: return(NULL);
624: }
625: memset(ret->locTab, 0 ,
626: XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
627: ret->locMax = XML_RANGESET_DEFAULT;
628: ret->locTab[ret->locNr++] = val;
629: }
630: return(ret);
631: }
632:
633: /**
634: * xmlXPtrLocationSetAdd:
635: * @cur: the initial range set
636: * @val: a new xmlXPathObjectPtr
637: *
638: * add a new xmlXPathObjectPtr to an existing LocationSet
639: * If the location already exist in the set @val is freed.
640: */
641: void
642: xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
643: int i;
644:
645: if ((cur == NULL) || (val == NULL)) return;
646:
647: /*
648: * check against doublons
649: */
650: for (i = 0;i < cur->locNr;i++) {
651: if (xmlXPtrRangesEqual(cur->locTab[i], val)) {
652: xmlXPathFreeObject(val);
653: return;
654: }
655: }
656:
657: /*
658: * grow the locTab if needed
659: */
660: if (cur->locMax == 0) {
661: cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
662: sizeof(xmlXPathObjectPtr));
663: if (cur->locTab == NULL) {
664: xmlXPtrErrMemory("adding location to set");
665: return;
666: }
667: memset(cur->locTab, 0 ,
668: XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
669: cur->locMax = XML_RANGESET_DEFAULT;
670: } else if (cur->locNr == cur->locMax) {
671: xmlXPathObjectPtr *temp;
672:
673: cur->locMax *= 2;
674: temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax *
675: sizeof(xmlXPathObjectPtr));
676: if (temp == NULL) {
677: xmlXPtrErrMemory("adding location to set");
678: return;
679: }
680: cur->locTab = temp;
681: }
682: cur->locTab[cur->locNr++] = val;
683: }
684:
685: /**
686: * xmlXPtrLocationSetMerge:
687: * @val1: the first LocationSet
688: * @val2: the second LocationSet
689: *
690: * Merges two rangesets, all ranges from @val2 are added to @val1
691: *
692: * Returns val1 once extended or NULL in case of error.
693: */
694: xmlLocationSetPtr
695: xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) {
696: int i;
697:
698: if (val1 == NULL) return(NULL);
699: if (val2 == NULL) return(val1);
700:
701: /*
702: * !!!!! this can be optimized a lot, knowing that both
703: * val1 and val2 already have unicity of their values.
704: */
705:
706: for (i = 0;i < val2->locNr;i++)
707: xmlXPtrLocationSetAdd(val1, val2->locTab[i]);
708:
709: return(val1);
710: }
711:
712: /**
713: * xmlXPtrLocationSetDel:
714: * @cur: the initial range set
715: * @val: an xmlXPathObjectPtr
716: *
717: * Removes an xmlXPathObjectPtr from an existing LocationSet
718: */
719: void
720: xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
721: int i;
722:
723: if (cur == NULL) return;
724: if (val == NULL) return;
725:
726: /*
727: * check against doublons
728: */
729: for (i = 0;i < cur->locNr;i++)
730: if (cur->locTab[i] == val) break;
731:
732: if (i >= cur->locNr) {
733: #ifdef DEBUG
734: xmlGenericError(xmlGenericErrorContext,
735: "xmlXPtrLocationSetDel: Range wasn't found in RangeList\n");
736: #endif
737: return;
738: }
739: cur->locNr--;
740: for (;i < cur->locNr;i++)
741: cur->locTab[i] = cur->locTab[i + 1];
742: cur->locTab[cur->locNr] = NULL;
743: }
744:
745: /**
746: * xmlXPtrLocationSetRemove:
747: * @cur: the initial range set
748: * @val: the index to remove
749: *
750: * Removes an entry from an existing LocationSet list.
751: */
752: void
753: xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) {
754: if (cur == NULL) return;
755: if (val >= cur->locNr) return;
756: cur->locNr--;
757: for (;val < cur->locNr;val++)
758: cur->locTab[val] = cur->locTab[val + 1];
759: cur->locTab[cur->locNr] = NULL;
760: }
761:
762: /**
763: * xmlXPtrFreeLocationSet:
764: * @obj: the xmlLocationSetPtr to free
765: *
766: * Free the LocationSet compound (not the actual ranges !).
767: */
768: void
769: xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) {
770: int i;
771:
772: if (obj == NULL) return;
773: if (obj->locTab != NULL) {
774: for (i = 0;i < obj->locNr; i++) {
775: xmlXPathFreeObject(obj->locTab[i]);
776: }
777: xmlFree(obj->locTab);
778: }
779: xmlFree(obj);
780: }
781:
782: /**
783: * xmlXPtrNewLocationSetNodes:
784: * @start: the start NodePtr value
785: * @end: the end NodePtr value or NULL
786: *
787: * Create a new xmlXPathObjectPtr of type LocationSet and initialize
788: * it with the single range made of the two nodes @start and @end
789: *
790: * Returns the newly created object.
791: */
792: xmlXPathObjectPtr
793: xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) {
794: xmlXPathObjectPtr ret;
795:
796: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
797: if (ret == NULL) {
798: xmlXPtrErrMemory("allocating locationset");
799: return(NULL);
800: }
801: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
802: ret->type = XPATH_LOCATIONSET;
803: if (end == NULL)
804: ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start));
805: else
806: ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end));
807: return(ret);
808: }
809:
810: /**
811: * xmlXPtrNewLocationSetNodeSet:
812: * @set: a node set
813: *
814: * Create a new xmlXPathObjectPtr of type LocationSet and initialize
815: * it with all the nodes from @set
816: *
817: * Returns the newly created object.
818: */
819: xmlXPathObjectPtr
820: xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) {
821: xmlXPathObjectPtr ret;
822:
823: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
824: if (ret == NULL) {
825: xmlXPtrErrMemory("allocating locationset");
826: return(NULL);
827: }
828: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
829: ret->type = XPATH_LOCATIONSET;
830: if (set != NULL) {
831: int i;
832: xmlLocationSetPtr newset;
833:
834: newset = xmlXPtrLocationSetCreate(NULL);
835: if (newset == NULL)
836: return(ret);
837:
838: for (i = 0;i < set->nodeNr;i++)
839: xmlXPtrLocationSetAdd(newset,
840: xmlXPtrNewCollapsedRange(set->nodeTab[i]));
841:
842: ret->user = (void *) newset;
843: }
844: return(ret);
845: }
846:
847: /**
848: * xmlXPtrWrapLocationSet:
849: * @val: the LocationSet value
850: *
851: * Wrap the LocationSet @val in a new xmlXPathObjectPtr
852: *
853: * Returns the newly created object.
854: */
855: xmlXPathObjectPtr
856: xmlXPtrWrapLocationSet(xmlLocationSetPtr val) {
857: xmlXPathObjectPtr ret;
858:
859: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
860: if (ret == NULL) {
861: xmlXPtrErrMemory("allocating locationset");
862: return(NULL);
863: }
864: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
865: ret->type = XPATH_LOCATIONSET;
866: ret->user = (void *) val;
867: return(ret);
868: }
869:
870: /************************************************************************
871: * *
872: * The parser *
873: * *
874: ************************************************************************/
875:
876: static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name);
877:
878: /*
879: * Macros for accessing the content. Those should be used only by the parser,
880: * and not exported.
881: *
882: * Dirty macros, i.e. one need to make assumption on the context to use them
883: *
884: * CUR_PTR return the current pointer to the xmlChar to be parsed.
885: * CUR returns the current xmlChar value, i.e. a 8 bit value
886: * in ISO-Latin or UTF-8.
887: * This should be used internally by the parser
888: * only to compare to ASCII values otherwise it would break when
889: * running with UTF-8 encoding.
890: * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
891: * to compare on ASCII based substring.
892: * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
893: * strings within the parser.
894: * CURRENT Returns the current char value, with the full decoding of
895: * UTF-8 if we are using this mode. It returns an int.
896: * NEXT Skip to the next character, this does the proper decoding
897: * in UTF-8 mode. It also pop-up unfinished entities on the fly.
898: * It returns the pointer to the current xmlChar.
899: */
900:
901: #define CUR (*ctxt->cur)
902: #define SKIP(val) ctxt->cur += (val)
903: #define NXT(val) ctxt->cur[(val)]
904: #define CUR_PTR ctxt->cur
905:
906: #define SKIP_BLANKS \
907: while (IS_BLANK_CH(*(ctxt->cur))) NEXT
908:
909: #define CURRENT (*ctxt->cur)
910: #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
911:
912: /*
913: * xmlXPtrGetChildNo:
914: * @ctxt: the XPointer Parser context
915: * @index: the child number
916: *
917: * Move the current node of the nodeset on the stack to the
918: * given child if found
919: */
920: static void
921: xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) {
922: xmlNodePtr cur = NULL;
923: xmlXPathObjectPtr obj;
924: xmlNodeSetPtr oldset;
925:
926: CHECK_TYPE(XPATH_NODESET);
927: obj = valuePop(ctxt);
928: oldset = obj->nodesetval;
929: if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) {
930: xmlXPathFreeObject(obj);
931: valuePush(ctxt, xmlXPathNewNodeSet(NULL));
932: return;
933: }
934: cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx);
935: if (cur == NULL) {
936: xmlXPathFreeObject(obj);
937: valuePush(ctxt, xmlXPathNewNodeSet(NULL));
938: return;
939: }
940: oldset->nodeTab[0] = cur;
941: valuePush(ctxt, obj);
942: }
943:
944: /**
945: * xmlXPtrEvalXPtrPart:
946: * @ctxt: the XPointer Parser context
947: * @name: the preparsed Scheme for the XPtrPart
948: *
949: * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
950: * | Scheme '(' SchemeSpecificExpr ')'
951: *
952: * Scheme ::= NCName - 'xpointer' [VC: Non-XPointer schemes]
953: *
954: * SchemeSpecificExpr ::= StringWithBalancedParens
955: *
956: * StringWithBalancedParens ::=
957: * [^()]* ('(' StringWithBalancedParens ')' [^()]*)*
958: * [VC: Parenthesis escaping]
959: *
960: * XPtrExpr ::= Expr [VC: Parenthesis escaping]
961: *
962: * VC: Parenthesis escaping:
963: * The end of an XPointer part is signaled by the right parenthesis ")"
964: * character that is balanced with the left parenthesis "(" character
965: * that began the part. Any unbalanced parenthesis character inside the
966: * expression, even within literals, must be escaped with a circumflex (^)
967: * character preceding it. If the expression contains any literal
968: * occurrences of the circumflex, each must be escaped with an additional
969: * circumflex (that is, ^^). If the unescaped parentheses in the expression
970: * are not balanced, a syntax error results.
971: *
972: * Parse and evaluate an XPtrPart. Basically it generates the unescaped
973: * string and if the scheme is 'xpointer' it will call the XPath interpreter.
974: *
975: * TODO: there is no new scheme registration mechanism
976: */
977:
978: static void
979: xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) {
980: xmlChar *buffer, *cur;
981: int len;
982: int level;
983:
984: if (name == NULL)
985: name = xmlXPathParseName(ctxt);
986: if (name == NULL)
987: XP_ERROR(XPATH_EXPR_ERROR);
988:
989: if (CUR != '(')
990: XP_ERROR(XPATH_EXPR_ERROR);
991: NEXT;
992: level = 1;
993:
994: len = xmlStrlen(ctxt->cur);
995: len++;
996: buffer = (xmlChar *) xmlMallocAtomic(len * sizeof (xmlChar));
997: if (buffer == NULL) {
998: xmlXPtrErrMemory("allocating buffer");
999: return;
1000: }
1001:
1002: cur = buffer;
1003: while (CUR != 0) {
1004: if (CUR == ')') {
1005: level--;
1006: if (level == 0) {
1007: NEXT;
1008: break;
1009: }
1010: *cur++ = CUR;
1011: } else if (CUR == '(') {
1012: level++;
1013: *cur++ = CUR;
1014: } else if (CUR == '^') {
1015: NEXT;
1016: if ((CUR == ')') || (CUR == '(') || (CUR == '^')) {
1017: *cur++ = CUR;
1018: } else {
1019: *cur++ = '^';
1020: *cur++ = CUR;
1021: }
1022: } else {
1023: *cur++ = CUR;
1024: }
1025: NEXT;
1026: }
1027: *cur = 0;
1028:
1029: if ((level != 0) && (CUR == 0)) {
1030: xmlFree(buffer);
1031: XP_ERROR(XPTR_SYNTAX_ERROR);
1032: }
1033:
1034: if (xmlStrEqual(name, (xmlChar *) "xpointer")) {
1035: const xmlChar *left = CUR_PTR;
1036:
1037: CUR_PTR = buffer;
1038: /*
1039: * To evaluate an xpointer scheme element (4.3) we need:
1040: * context initialized to the root
1041: * context position initalized to 1
1042: * context size initialized to 1
1043: */
1044: ctxt->context->node = (xmlNodePtr)ctxt->context->doc;
1045: ctxt->context->proximityPosition = 1;
1046: ctxt->context->contextSize = 1;
1047: xmlXPathEvalExpr(ctxt);
1048: CUR_PTR=left;
1049: } else if (xmlStrEqual(name, (xmlChar *) "element")) {
1050: const xmlChar *left = CUR_PTR;
1051: xmlChar *name2;
1052:
1053: CUR_PTR = buffer;
1054: if (buffer[0] == '/') {
1055: xmlXPathRoot(ctxt);
1056: xmlXPtrEvalChildSeq(ctxt, NULL);
1057: } else {
1058: name2 = xmlXPathParseName(ctxt);
1059: if (name2 == NULL) {
1060: CUR_PTR = left;
1061: xmlFree(buffer);
1062: XP_ERROR(XPATH_EXPR_ERROR);
1063: }
1064: xmlXPtrEvalChildSeq(ctxt, name2);
1065: }
1066: CUR_PTR = left;
1067: #ifdef XPTR_XMLNS_SCHEME
1068: } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
1069: const xmlChar *left = CUR_PTR;
1070: xmlChar *prefix;
1071: xmlChar *URI;
1072: xmlURIPtr value;
1073:
1074: CUR_PTR = buffer;
1075: prefix = xmlXPathParseNCName(ctxt);
1076: if (prefix == NULL) {
1077: xmlFree(buffer);
1078: xmlFree(name);
1079: XP_ERROR(XPTR_SYNTAX_ERROR);
1080: }
1081: SKIP_BLANKS;
1082: if (CUR != '=') {
1083: xmlFree(prefix);
1084: xmlFree(buffer);
1085: xmlFree(name);
1086: XP_ERROR(XPTR_SYNTAX_ERROR);
1087: }
1088: NEXT;
1089: SKIP_BLANKS;
1090: /* @@ check escaping in the XPointer WD */
1091:
1092: value = xmlParseURI((const char *)ctxt->cur);
1093: if (value == NULL) {
1094: xmlFree(prefix);
1095: xmlFree(buffer);
1096: xmlFree(name);
1097: XP_ERROR(XPTR_SYNTAX_ERROR);
1098: }
1099: URI = xmlSaveUri(value);
1100: xmlFreeURI(value);
1101: if (URI == NULL) {
1102: xmlFree(prefix);
1103: xmlFree(buffer);
1104: xmlFree(name);
1105: XP_ERROR(XPATH_MEMORY_ERROR);
1106: }
1107:
1108: xmlXPathRegisterNs(ctxt->context, prefix, URI);
1109: CUR_PTR = left;
1110: xmlFree(URI);
1111: xmlFree(prefix);
1112: #endif /* XPTR_XMLNS_SCHEME */
1113: } else {
1114: xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME,
1115: "unsupported scheme '%s'\n", name);
1116: }
1117: xmlFree(buffer);
1118: xmlFree(name);
1119: }
1120:
1121: /**
1122: * xmlXPtrEvalFullXPtr:
1123: * @ctxt: the XPointer Parser context
1124: * @name: the preparsed Scheme for the first XPtrPart
1125: *
1126: * FullXPtr ::= XPtrPart (S? XPtrPart)*
1127: *
1128: * As the specs says:
1129: * -----------
1130: * When multiple XPtrParts are provided, they must be evaluated in
1131: * left-to-right order. If evaluation of one part fails, the nexti
1132: * is evaluated. The following conditions cause XPointer part failure:
1133: *
1134: * - An unknown scheme
1135: * - A scheme that does not locate any sub-resource present in the resource
1136: * - A scheme that is not applicable to the media type of the resource
1137: *
1138: * The XPointer application must consume a failed XPointer part and
1139: * attempt to evaluate the next one, if any. The result of the first
1140: * XPointer part whose evaluation succeeds is taken to be the fragment
1141: * located by the XPointer as a whole. If all the parts fail, the result
1142: * for the XPointer as a whole is a sub-resource error.
1143: * -----------
1144: *
1145: * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
1146: * expressions or other schemes.
1147: */
1148: static void
1149: xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
1150: if (name == NULL)
1151: name = xmlXPathParseName(ctxt);
1152: if (name == NULL)
1153: XP_ERROR(XPATH_EXPR_ERROR);
1154: while (name != NULL) {
1155: ctxt->error = XPATH_EXPRESSION_OK;
1156: xmlXPtrEvalXPtrPart(ctxt, name);
1157:
1158: /* in case of syntax error, break here */
1159: if ((ctxt->error != XPATH_EXPRESSION_OK) &&
1160: (ctxt->error != XML_XPTR_UNKNOWN_SCHEME))
1161: return;
1162:
1163: /*
1164: * If the returned value is a non-empty nodeset
1165: * or location set, return here.
1166: */
1167: if (ctxt->value != NULL) {
1168: xmlXPathObjectPtr obj = ctxt->value;
1169:
1170: switch (obj->type) {
1171: case XPATH_LOCATIONSET: {
1172: xmlLocationSetPtr loc = ctxt->value->user;
1173: if ((loc != NULL) && (loc->locNr > 0))
1174: return;
1175: break;
1176: }
1177: case XPATH_NODESET: {
1178: xmlNodeSetPtr loc = ctxt->value->nodesetval;
1179: if ((loc != NULL) && (loc->nodeNr > 0))
1180: return;
1181: break;
1182: }
1183: default:
1184: break;
1185: }
1186:
1187: /*
1188: * Evaluating to improper values is equivalent to
1189: * a sub-resource error, clean-up the stack
1190: */
1191: do {
1192: obj = valuePop(ctxt);
1193: if (obj != NULL) {
1194: xmlXPathFreeObject(obj);
1195: }
1196: } while (obj != NULL);
1197: }
1198:
1199: /*
1200: * Is there another XPointer part.
1201: */
1202: SKIP_BLANKS;
1203: name = xmlXPathParseName(ctxt);
1204: }
1205: }
1206:
1207: /**
1208: * xmlXPtrEvalChildSeq:
1209: * @ctxt: the XPointer Parser context
1210: * @name: a possible ID name of the child sequence
1211: *
1212: * ChildSeq ::= '/1' ('/' [0-9]*)*
1213: * | Name ('/' [0-9]*)+
1214: *
1215: * Parse and evaluate a Child Sequence. This routine also handle the
1216: * case of a Bare Name used to get a document ID.
1217: */
1218: static void
1219: xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
1220: /*
1221: * XPointer don't allow by syntax to address in mutirooted trees
1222: * this might prove useful in some cases, warn about it.
1223: */
1224: if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
1225: xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START,
1226: "warning: ChildSeq not starting by /1\n", NULL);
1227: }
1228:
1229: if (name != NULL) {
1230: valuePush(ctxt, xmlXPathNewString(name));
1231: xmlFree(name);
1232: xmlXPathIdFunction(ctxt, 1);
1233: CHECK_ERROR;
1234: }
1235:
1236: while (CUR == '/') {
1237: int child = 0;
1238: NEXT;
1239:
1240: while ((CUR >= '0') && (CUR <= '9')) {
1241: child = child * 10 + (CUR - '0');
1242: NEXT;
1243: }
1244: xmlXPtrGetChildNo(ctxt, child);
1245: }
1246: }
1247:
1248:
1249: /**
1250: * xmlXPtrEvalXPointer:
1251: * @ctxt: the XPointer Parser context
1252: *
1253: * XPointer ::= Name
1254: * | ChildSeq
1255: * | FullXPtr
1256: *
1257: * Parse and evaluate an XPointer
1258: */
1259: static void
1260: xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
1261: if (ctxt->valueTab == NULL) {
1262: /* Allocate the value stack */
1263: ctxt->valueTab = (xmlXPathObjectPtr *)
1264: xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
1265: if (ctxt->valueTab == NULL) {
1266: xmlXPtrErrMemory("allocating evaluation context");
1267: return;
1268: }
1269: ctxt->valueNr = 0;
1270: ctxt->valueMax = 10;
1271: ctxt->value = NULL;
1272: }
1273: SKIP_BLANKS;
1274: if (CUR == '/') {
1275: xmlXPathRoot(ctxt);
1276: xmlXPtrEvalChildSeq(ctxt, NULL);
1277: } else {
1278: xmlChar *name;
1279:
1280: name = xmlXPathParseName(ctxt);
1281: if (name == NULL)
1282: XP_ERROR(XPATH_EXPR_ERROR);
1283: if (CUR == '(') {
1284: xmlXPtrEvalFullXPtr(ctxt, name);
1285: /* Short evaluation */
1286: return;
1287: } else {
1288: /* this handle both Bare Names and Child Sequences */
1289: xmlXPtrEvalChildSeq(ctxt, name);
1290: }
1291: }
1292: SKIP_BLANKS;
1293: if (CUR != 0)
1294: XP_ERROR(XPATH_EXPR_ERROR);
1295: }
1296:
1297:
1298: /************************************************************************
1299: * *
1300: * General routines *
1301: * *
1302: ************************************************************************/
1303:
1304: static
1305: void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
1306: static
1307: void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1308: static
1309: void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1310: static
1311: void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
1312: static
1313: void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
1314: static
1315: void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
1316: static
1317: void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
1318:
1319: /**
1320: * xmlXPtrNewContext:
1321: * @doc: the XML document
1322: * @here: the node that directly contains the XPointer being evaluated or NULL
1323: * @origin: the element from which a user or program initiated traversal of
1324: * the link, or NULL.
1325: *
1326: * Create a new XPointer context
1327: *
1328: * Returns the xmlXPathContext just allocated.
1329: */
1330: xmlXPathContextPtr
1331: xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
1332: xmlXPathContextPtr ret;
1333:
1334: ret = xmlXPathNewContext(doc);
1335: if (ret == NULL)
1336: return(ret);
1337: ret->xptr = 1;
1338: ret->here = here;
1339: ret->origin = origin;
1340:
1341: xmlXPathRegisterFunc(ret, (xmlChar *)"range-to",
1342: xmlXPtrRangeToFunction);
1343: xmlXPathRegisterFunc(ret, (xmlChar *)"range",
1344: xmlXPtrRangeFunction);
1345: xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
1346: xmlXPtrRangeInsideFunction);
1347: xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
1348: xmlXPtrStringRangeFunction);
1349: xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
1350: xmlXPtrStartPointFunction);
1351: xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
1352: xmlXPtrEndPointFunction);
1353: xmlXPathRegisterFunc(ret, (xmlChar *)"here",
1354: xmlXPtrHereFunction);
1355: xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
1356: xmlXPtrOriginFunction);
1357:
1358: return(ret);
1359: }
1360:
1361: /**
1362: * xmlXPtrEval:
1363: * @str: the XPointer expression
1364: * @ctx: the XPointer context
1365: *
1366: * Evaluate the XPath Location Path in the given context.
1367: *
1368: * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
1369: * the caller has to free the object.
1370: */
1371: xmlXPathObjectPtr
1372: xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
1373: xmlXPathParserContextPtr ctxt;
1374: xmlXPathObjectPtr res = NULL, tmp;
1375: xmlXPathObjectPtr init = NULL;
1376: int stack = 0;
1377:
1378: xmlXPathInit();
1379:
1380: if ((ctx == NULL) || (str == NULL))
1381: return(NULL);
1382:
1383: ctxt = xmlXPathNewParserContext(str, ctx);
1384: ctxt->xptr = 1;
1385: xmlXPtrEvalXPointer(ctxt);
1386:
1387: if ((ctxt->value != NULL) &&
1388: (ctxt->value->type != XPATH_NODESET) &&
1389: (ctxt->value->type != XPATH_LOCATIONSET)) {
1390: xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED,
1391: "xmlXPtrEval: evaluation failed to return a node set\n",
1392: NULL);
1393: } else {
1394: res = valuePop(ctxt);
1395: }
1396:
1397: do {
1398: tmp = valuePop(ctxt);
1399: if (tmp != NULL) {
1400: if (tmp != init) {
1401: if (tmp->type == XPATH_NODESET) {
1402: /*
1403: * Evaluation may push a root nodeset which is unused
1404: */
1405: xmlNodeSetPtr set;
1406: set = tmp->nodesetval;
1407: if ((set->nodeNr != 1) ||
1408: (set->nodeTab[0] != (xmlNodePtr) ctx->doc))
1409: stack++;
1410: } else
1411: stack++;
1412: }
1413: xmlXPathFreeObject(tmp);
1414: }
1415: } while (tmp != NULL);
1416: if (stack != 0) {
1417: xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS,
1418: "xmlXPtrEval: object(s) left on the eval stack\n",
1419: NULL);
1420: }
1421: if (ctxt->error != XPATH_EXPRESSION_OK) {
1422: xmlXPathFreeObject(res);
1423: res = NULL;
1424: }
1425:
1426: xmlXPathFreeParserContext(ctxt);
1427: return(res);
1428: }
1429:
1430: /**
1431: * xmlXPtrBuildRangeNodeList:
1432: * @range: a range object
1433: *
1434: * Build a node list tree copy of the range
1435: *
1436: * Returns an xmlNodePtr list or NULL.
1437: * the caller has to free the node tree.
1438: */
1439: static xmlNodePtr
1440: xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) {
1441: /* pointers to generated nodes */
1442: xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
1443: /* pointers to traversal nodes */
1444: xmlNodePtr start, cur, end;
1445: int index1, index2;
1446:
1447: if (range == NULL)
1448: return(NULL);
1449: if (range->type != XPATH_RANGE)
1450: return(NULL);
1451: start = (xmlNodePtr) range->user;
1452:
1453: if (start == NULL)
1454: return(NULL);
1455: end = range->user2;
1456: if (end == NULL)
1457: return(xmlCopyNode(start, 1));
1458:
1459: cur = start;
1460: index1 = range->index;
1461: index2 = range->index2;
1462: while (cur != NULL) {
1463: if (cur == end) {
1464: if (cur->type == XML_TEXT_NODE) {
1465: const xmlChar *content = cur->content;
1466: int len;
1467:
1468: if (content == NULL) {
1469: tmp = xmlNewTextLen(NULL, 0);
1470: } else {
1471: len = index2;
1472: if ((cur == start) && (index1 > 1)) {
1473: content += (index1 - 1);
1474: len -= (index1 - 1);
1475: index1 = 0;
1476: } else {
1477: len = index2;
1478: }
1479: tmp = xmlNewTextLen(content, len);
1480: }
1481: /* single sub text node selection */
1482: if (list == NULL)
1483: return(tmp);
1484: /* prune and return full set */
1485: if (last != NULL)
1486: xmlAddNextSibling(last, tmp);
1487: else
1488: xmlAddChild(parent, tmp);
1489: return(list);
1490: } else {
1491: tmp = xmlCopyNode(cur, 0);
1492: if (list == NULL)
1493: list = tmp;
1494: else {
1495: if (last != NULL)
1496: xmlAddNextSibling(last, tmp);
1497: else
1498: xmlAddChild(parent, tmp);
1499: }
1500: last = NULL;
1501: parent = tmp;
1502:
1503: if (index2 > 1) {
1504: end = xmlXPtrGetNthChild(cur, index2 - 1);
1505: index2 = 0;
1506: }
1507: if ((cur == start) && (index1 > 1)) {
1508: cur = xmlXPtrGetNthChild(cur, index1 - 1);
1509: index1 = 0;
1510: } else {
1511: cur = cur->children;
1512: }
1513: /*
1514: * Now gather the remaining nodes from cur to end
1515: */
1516: continue; /* while */
1517: }
1518: } else if ((cur == start) &&
1519: (list == NULL) /* looks superfluous but ... */ ) {
1520: if ((cur->type == XML_TEXT_NODE) ||
1521: (cur->type == XML_CDATA_SECTION_NODE)) {
1522: const xmlChar *content = cur->content;
1523:
1524: if (content == NULL) {
1525: tmp = xmlNewTextLen(NULL, 0);
1526: } else {
1527: if (index1 > 1) {
1528: content += (index1 - 1);
1529: }
1530: tmp = xmlNewText(content);
1531: }
1532: last = list = tmp;
1533: } else {
1534: if ((cur == start) && (index1 > 1)) {
1535: tmp = xmlCopyNode(cur, 0);
1536: list = tmp;
1537: parent = tmp;
1538: last = NULL;
1539: cur = xmlXPtrGetNthChild(cur, index1 - 1);
1540: index1 = 0;
1541: /*
1542: * Now gather the remaining nodes from cur to end
1543: */
1544: continue; /* while */
1545: }
1546: tmp = xmlCopyNode(cur, 1);
1547: list = tmp;
1548: parent = NULL;
1549: last = tmp;
1550: }
1551: } else {
1552: tmp = NULL;
1553: switch (cur->type) {
1554: case XML_DTD_NODE:
1555: case XML_ELEMENT_DECL:
1556: case XML_ATTRIBUTE_DECL:
1557: case XML_ENTITY_NODE:
1558: /* Do not copy DTD informations */
1559: break;
1560: case XML_ENTITY_DECL:
1561: TODO /* handle crossing entities -> stack needed */
1562: break;
1563: case XML_XINCLUDE_START:
1564: case XML_XINCLUDE_END:
1565: /* don't consider it part of the tree content */
1566: break;
1567: case XML_ATTRIBUTE_NODE:
1568: /* Humm, should not happen ! */
1569: STRANGE
1570: break;
1571: default:
1572: tmp = xmlCopyNode(cur, 1);
1573: break;
1574: }
1575: if (tmp != NULL) {
1576: if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
1577: STRANGE
1578: return(NULL);
1579: }
1580: if (last != NULL)
1581: xmlAddNextSibling(last, tmp);
1582: else {
1583: xmlAddChild(parent, tmp);
1584: last = tmp;
1585: }
1586: }
1587: }
1588: /*
1589: * Skip to next node in document order
1590: */
1591: if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
1592: STRANGE
1593: return(NULL);
1594: }
1595: cur = xmlXPtrAdvanceNode(cur, NULL);
1596: }
1597: return(list);
1598: }
1599:
1600: /**
1601: * xmlXPtrBuildNodeList:
1602: * @obj: the XPointer result from the evaluation.
1603: *
1604: * Build a node list tree copy of the XPointer result.
1605: * This will drop Attributes and Namespace declarations.
1606: *
1607: * Returns an xmlNodePtr list or NULL.
1608: * the caller has to free the node tree.
1609: */
1610: xmlNodePtr
1611: xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) {
1612: xmlNodePtr list = NULL, last = NULL;
1613: int i;
1614:
1615: if (obj == NULL)
1616: return(NULL);
1617: switch (obj->type) {
1618: case XPATH_NODESET: {
1619: xmlNodeSetPtr set = obj->nodesetval;
1620: if (set == NULL)
1621: return(NULL);
1622: for (i = 0;i < set->nodeNr;i++) {
1623: if (set->nodeTab[i] == NULL)
1624: continue;
1625: switch (set->nodeTab[i]->type) {
1626: case XML_TEXT_NODE:
1627: case XML_CDATA_SECTION_NODE:
1628: case XML_ELEMENT_NODE:
1629: case XML_ENTITY_REF_NODE:
1630: case XML_ENTITY_NODE:
1631: case XML_PI_NODE:
1632: case XML_COMMENT_NODE:
1633: case XML_DOCUMENT_NODE:
1634: case XML_HTML_DOCUMENT_NODE:
1635: #ifdef LIBXML_DOCB_ENABLED
1636: case XML_DOCB_DOCUMENT_NODE:
1637: #endif
1638: case XML_XINCLUDE_START:
1639: case XML_XINCLUDE_END:
1640: break;
1641: case XML_ATTRIBUTE_NODE:
1642: case XML_NAMESPACE_DECL:
1643: case XML_DOCUMENT_TYPE_NODE:
1644: case XML_DOCUMENT_FRAG_NODE:
1645: case XML_NOTATION_NODE:
1646: case XML_DTD_NODE:
1647: case XML_ELEMENT_DECL:
1648: case XML_ATTRIBUTE_DECL:
1649: case XML_ENTITY_DECL:
1650: continue; /* for */
1651: }
1652: if (last == NULL)
1653: list = last = xmlCopyNode(set->nodeTab[i], 1);
1654: else {
1655: xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1));
1656: if (last->next != NULL)
1657: last = last->next;
1658: }
1659: }
1660: break;
1661: }
1662: case XPATH_LOCATIONSET: {
1663: xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1664: if (set == NULL)
1665: return(NULL);
1666: for (i = 0;i < set->locNr;i++) {
1667: if (last == NULL)
1668: list = last = xmlXPtrBuildNodeList(set->locTab[i]);
1669: else
1670: xmlAddNextSibling(last,
1671: xmlXPtrBuildNodeList(set->locTab[i]));
1672: if (last != NULL) {
1673: while (last->next != NULL)
1674: last = last->next;
1675: }
1676: }
1677: break;
1678: }
1679: case XPATH_RANGE:
1680: return(xmlXPtrBuildRangeNodeList(obj));
1681: case XPATH_POINT:
1682: return(xmlCopyNode(obj->user, 0));
1683: default:
1684: break;
1685: }
1686: return(list);
1687: }
1688:
1689: /************************************************************************
1690: * *
1691: * XPointer functions *
1692: * *
1693: ************************************************************************/
1694:
1695: /**
1696: * xmlXPtrNbLocChildren:
1697: * @node: an xmlNodePtr
1698: *
1699: * Count the number of location children of @node or the length of the
1700: * string value in case of text/PI/Comments nodes
1701: *
1702: * Returns the number of location children
1703: */
1704: static int
1705: xmlXPtrNbLocChildren(xmlNodePtr node) {
1706: int ret = 0;
1707: if (node == NULL)
1708: return(-1);
1709: switch (node->type) {
1710: case XML_HTML_DOCUMENT_NODE:
1711: case XML_DOCUMENT_NODE:
1712: case XML_ELEMENT_NODE:
1713: node = node->children;
1714: while (node != NULL) {
1715: if (node->type == XML_ELEMENT_NODE)
1716: ret++;
1717: node = node->next;
1718: }
1719: break;
1720: case XML_ATTRIBUTE_NODE:
1721: return(-1);
1722:
1723: case XML_PI_NODE:
1724: case XML_COMMENT_NODE:
1725: case XML_TEXT_NODE:
1726: case XML_CDATA_SECTION_NODE:
1727: case XML_ENTITY_REF_NODE:
1728: ret = xmlStrlen(node->content);
1729: break;
1730: default:
1731: return(-1);
1732: }
1733: return(ret);
1734: }
1735:
1736: /**
1737: * xmlXPtrHereFunction:
1738: * @ctxt: the XPointer Parser context
1739: * @nargs: the number of args
1740: *
1741: * Function implementing here() operation
1742: * as described in 5.4.3
1743: */
1744: static void
1745: xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1746: CHECK_ARITY(0);
1747:
1748: if (ctxt->context->here == NULL)
1749: XP_ERROR(XPTR_SYNTAX_ERROR);
1750:
1751: valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL));
1752: }
1753:
1754: /**
1755: * xmlXPtrOriginFunction:
1756: * @ctxt: the XPointer Parser context
1757: * @nargs: the number of args
1758: *
1759: * Function implementing origin() operation
1760: * as described in 5.4.3
1761: */
1762: static void
1763: xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1764: CHECK_ARITY(0);
1765:
1766: if (ctxt->context->origin == NULL)
1767: XP_ERROR(XPTR_SYNTAX_ERROR);
1768:
1769: valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL));
1770: }
1771:
1772: /**
1773: * xmlXPtrStartPointFunction:
1774: * @ctxt: the XPointer Parser context
1775: * @nargs: the number of args
1776: *
1777: * Function implementing start-point() operation
1778: * as described in 5.4.3
1779: * ----------------
1780: * location-set start-point(location-set)
1781: *
1782: * For each location x in the argument location-set, start-point adds a
1783: * location of type point to the result location-set. That point represents
1784: * the start point of location x and is determined by the following rules:
1785: *
1786: * - If x is of type point, the start point is x.
1787: * - If x is of type range, the start point is the start point of x.
1788: * - If x is of type root, element, text, comment, or processing instruction,
1789: * - the container node of the start point is x and the index is 0.
1790: * - If x is of type attribute or namespace, the function must signal a
1791: * syntax error.
1792: * ----------------
1793: *
1794: */
1795: static void
1796: xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1797: xmlXPathObjectPtr tmp, obj, point;
1798: xmlLocationSetPtr newset = NULL;
1799: xmlLocationSetPtr oldset = NULL;
1800:
1801: CHECK_ARITY(1);
1802: if ((ctxt->value == NULL) ||
1803: ((ctxt->value->type != XPATH_LOCATIONSET) &&
1804: (ctxt->value->type != XPATH_NODESET)))
1805: XP_ERROR(XPATH_INVALID_TYPE)
1806:
1807: obj = valuePop(ctxt);
1808: if (obj->type == XPATH_NODESET) {
1809: /*
1810: * First convert to a location set
1811: */
1812: tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
1813: xmlXPathFreeObject(obj);
1814: obj = tmp;
1815: }
1816:
1817: newset = xmlXPtrLocationSetCreate(NULL);
1818: if (newset == NULL) {
1819: xmlXPathFreeObject(obj);
1820: XP_ERROR(XPATH_MEMORY_ERROR);
1821: }
1822: oldset = (xmlLocationSetPtr) obj->user;
1823: if (oldset != NULL) {
1824: int i;
1825:
1826: for (i = 0; i < oldset->locNr; i++) {
1827: tmp = oldset->locTab[i];
1828: if (tmp == NULL)
1829: continue;
1830: point = NULL;
1831: switch (tmp->type) {
1832: case XPATH_POINT:
1833: point = xmlXPtrNewPoint(tmp->user, tmp->index);
1834: break;
1835: case XPATH_RANGE: {
1836: xmlNodePtr node = tmp->user;
1837: if (node != NULL) {
1838: if (node->type == XML_ATTRIBUTE_NODE) {
1839: /* TODO: Namespace Nodes ??? */
1840: xmlXPathFreeObject(obj);
1841: xmlXPtrFreeLocationSet(newset);
1842: XP_ERROR(XPTR_SYNTAX_ERROR);
1843: }
1844: point = xmlXPtrNewPoint(node, tmp->index);
1845: }
1846: break;
1847: }
1848: default:
1849: /*** Should we raise an error ?
1850: xmlXPathFreeObject(obj);
1851: xmlXPathFreeObject(newset);
1852: XP_ERROR(XPATH_INVALID_TYPE)
1853: ***/
1854: break;
1855: }
1856: if (point != NULL)
1857: xmlXPtrLocationSetAdd(newset, point);
1858: }
1859: }
1860: xmlXPathFreeObject(obj);
1861: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
1862: }
1863:
1864: /**
1865: * xmlXPtrEndPointFunction:
1866: * @ctxt: the XPointer Parser context
1867: * @nargs: the number of args
1868: *
1869: * Function implementing end-point() operation
1870: * as described in 5.4.3
1871: * ----------------------------
1872: * location-set end-point(location-set)
1873: *
1874: * For each location x in the argument location-set, end-point adds a
1875: * location of type point to the result location-set. That point represents
1876: * the end point of location x and is determined by the following rules:
1877: *
1878: * - If x is of type point, the resulting point is x.
1879: * - If x is of type range, the resulting point is the end point of x.
1880: * - If x is of type root or element, the container node of the resulting
1881: * point is x and the index is the number of location children of x.
1882: * - If x is of type text, comment, or processing instruction, the container
1883: * node of the resulting point is x and the index is the length of the
1884: * string-value of x.
1885: * - If x is of type attribute or namespace, the function must signal a
1886: * syntax error.
1887: * ----------------------------
1888: */
1889: static void
1890: xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1891: xmlXPathObjectPtr tmp, obj, point;
1892: xmlLocationSetPtr newset = NULL;
1893: xmlLocationSetPtr oldset = NULL;
1894:
1895: CHECK_ARITY(1);
1896: if ((ctxt->value == NULL) ||
1897: ((ctxt->value->type != XPATH_LOCATIONSET) &&
1898: (ctxt->value->type != XPATH_NODESET)))
1899: XP_ERROR(XPATH_INVALID_TYPE)
1900:
1901: obj = valuePop(ctxt);
1902: if (obj->type == XPATH_NODESET) {
1903: /*
1904: * First convert to a location set
1905: */
1906: tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
1907: xmlXPathFreeObject(obj);
1908: obj = tmp;
1909: }
1910:
1911: newset = xmlXPtrLocationSetCreate(NULL);
1912: oldset = (xmlLocationSetPtr) obj->user;
1913: if (oldset != NULL) {
1914: int i;
1915:
1916: for (i = 0; i < oldset->locNr; i++) {
1917: tmp = oldset->locTab[i];
1918: if (tmp == NULL)
1919: continue;
1920: point = NULL;
1921: switch (tmp->type) {
1922: case XPATH_POINT:
1923: point = xmlXPtrNewPoint(tmp->user, tmp->index);
1924: break;
1925: case XPATH_RANGE: {
1926: xmlNodePtr node = tmp->user2;
1927: if (node != NULL) {
1928: if (node->type == XML_ATTRIBUTE_NODE) {
1929: /* TODO: Namespace Nodes ??? */
1930: xmlXPathFreeObject(obj);
1931: xmlXPtrFreeLocationSet(newset);
1932: XP_ERROR(XPTR_SYNTAX_ERROR);
1933: }
1934: point = xmlXPtrNewPoint(node, tmp->index2);
1935: } else if (tmp->user == NULL) {
1936: point = xmlXPtrNewPoint(node,
1937: xmlXPtrNbLocChildren(node));
1938: }
1939: break;
1940: }
1941: default:
1942: /*** Should we raise an error ?
1943: xmlXPathFreeObject(obj);
1944: xmlXPathFreeObject(newset);
1945: XP_ERROR(XPATH_INVALID_TYPE)
1946: ***/
1947: break;
1948: }
1949: if (point != NULL)
1950: xmlXPtrLocationSetAdd(newset, point);
1951: }
1952: }
1953: xmlXPathFreeObject(obj);
1954: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
1955: }
1956:
1957:
1958: /**
1959: * xmlXPtrCoveringRange:
1960: * @ctxt: the XPointer Parser context
1961: * @loc: the location for which the covering range must be computed
1962: *
1963: * A covering range is a range that wholly encompasses a location
1964: * Section 5.3.3. Covering Ranges for All Location Types
1965: * http://www.w3.org/TR/xptr#N2267
1966: *
1967: * Returns a new location or NULL in case of error
1968: */
1969: static xmlXPathObjectPtr
1970: xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
1971: if (loc == NULL)
1972: return(NULL);
1973: if ((ctxt == NULL) || (ctxt->context == NULL) ||
1974: (ctxt->context->doc == NULL))
1975: return(NULL);
1976: switch (loc->type) {
1977: case XPATH_POINT:
1978: return(xmlXPtrNewRange(loc->user, loc->index,
1979: loc->user, loc->index));
1980: case XPATH_RANGE:
1981: if (loc->user2 != NULL) {
1982: return(xmlXPtrNewRange(loc->user, loc->index,
1983: loc->user2, loc->index2));
1984: } else {
1985: xmlNodePtr node = (xmlNodePtr) loc->user;
1986: if (node == (xmlNodePtr) ctxt->context->doc) {
1987: return(xmlXPtrNewRange(node, 0, node,
1988: xmlXPtrGetArity(node)));
1989: } else {
1990: switch (node->type) {
1991: case XML_ATTRIBUTE_NODE:
1992: /* !!! our model is slightly different than XPath */
1993: return(xmlXPtrNewRange(node, 0, node,
1994: xmlXPtrGetArity(node)));
1995: case XML_ELEMENT_NODE:
1996: case XML_TEXT_NODE:
1997: case XML_CDATA_SECTION_NODE:
1998: case XML_ENTITY_REF_NODE:
1999: case XML_PI_NODE:
2000: case XML_COMMENT_NODE:
2001: case XML_DOCUMENT_NODE:
2002: case XML_NOTATION_NODE:
2003: case XML_HTML_DOCUMENT_NODE: {
2004: int indx = xmlXPtrGetIndex(node);
2005:
2006: node = node->parent;
2007: return(xmlXPtrNewRange(node, indx - 1,
2008: node, indx + 1));
2009: }
2010: default:
2011: return(NULL);
2012: }
2013: }
2014: }
2015: default:
2016: TODO /* missed one case ??? */
2017: }
2018: return(NULL);
2019: }
2020:
2021: /**
2022: * xmlXPtrRangeFunction:
2023: * @ctxt: the XPointer Parser context
2024: * @nargs: the number of args
2025: *
2026: * Function implementing the range() function 5.4.3
2027: * location-set range(location-set )
2028: *
2029: * The range function returns ranges covering the locations in
2030: * the argument location-set. For each location x in the argument
2031: * location-set, a range location representing the covering range of
2032: * x is added to the result location-set.
2033: */
2034: static void
2035: xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2036: int i;
2037: xmlXPathObjectPtr set;
2038: xmlLocationSetPtr oldset;
2039: xmlLocationSetPtr newset;
2040:
2041: CHECK_ARITY(1);
2042: if ((ctxt->value == NULL) ||
2043: ((ctxt->value->type != XPATH_LOCATIONSET) &&
2044: (ctxt->value->type != XPATH_NODESET)))
2045: XP_ERROR(XPATH_INVALID_TYPE)
2046:
2047: set = valuePop(ctxt);
2048: if (set->type == XPATH_NODESET) {
2049: xmlXPathObjectPtr tmp;
2050:
2051: /*
2052: * First convert to a location set
2053: */
2054: tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2055: xmlXPathFreeObject(set);
2056: set = tmp;
2057: }
2058: oldset = (xmlLocationSetPtr) set->user;
2059:
2060: /*
2061: * The loop is to compute the covering range for each item and add it
2062: */
2063: newset = xmlXPtrLocationSetCreate(NULL);
2064: for (i = 0;i < oldset->locNr;i++) {
2065: xmlXPtrLocationSetAdd(newset,
2066: xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
2067: }
2068:
2069: /*
2070: * Save the new value and cleanup
2071: */
2072: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2073: xmlXPathFreeObject(set);
2074: }
2075:
2076: /**
2077: * xmlXPtrInsideRange:
2078: * @ctxt: the XPointer Parser context
2079: * @loc: the location for which the inside range must be computed
2080: *
2081: * A inside range is a range described in the range-inside() description
2082: *
2083: * Returns a new location or NULL in case of error
2084: */
2085: static xmlXPathObjectPtr
2086: xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
2087: if (loc == NULL)
2088: return(NULL);
2089: if ((ctxt == NULL) || (ctxt->context == NULL) ||
2090: (ctxt->context->doc == NULL))
2091: return(NULL);
2092: switch (loc->type) {
2093: case XPATH_POINT: {
2094: xmlNodePtr node = (xmlNodePtr) loc->user;
2095: switch (node->type) {
2096: case XML_PI_NODE:
2097: case XML_COMMENT_NODE:
2098: case XML_TEXT_NODE:
2099: case XML_CDATA_SECTION_NODE: {
2100: if (node->content == NULL) {
2101: return(xmlXPtrNewRange(node, 0, node, 0));
2102: } else {
2103: return(xmlXPtrNewRange(node, 0, node,
2104: xmlStrlen(node->content)));
2105: }
2106: }
2107: case XML_ATTRIBUTE_NODE:
2108: case XML_ELEMENT_NODE:
2109: case XML_ENTITY_REF_NODE:
2110: case XML_DOCUMENT_NODE:
2111: case XML_NOTATION_NODE:
2112: case XML_HTML_DOCUMENT_NODE: {
2113: return(xmlXPtrNewRange(node, 0, node,
2114: xmlXPtrGetArity(node)));
2115: }
2116: default:
2117: break;
2118: }
2119: return(NULL);
2120: }
2121: case XPATH_RANGE: {
2122: xmlNodePtr node = (xmlNodePtr) loc->user;
2123: if (loc->user2 != NULL) {
2124: return(xmlXPtrNewRange(node, loc->index,
2125: loc->user2, loc->index2));
2126: } else {
2127: switch (node->type) {
2128: case XML_PI_NODE:
2129: case XML_COMMENT_NODE:
2130: case XML_TEXT_NODE:
2131: case XML_CDATA_SECTION_NODE: {
2132: if (node->content == NULL) {
2133: return(xmlXPtrNewRange(node, 0, node, 0));
2134: } else {
2135: return(xmlXPtrNewRange(node, 0, node,
2136: xmlStrlen(node->content)));
2137: }
2138: }
2139: case XML_ATTRIBUTE_NODE:
2140: case XML_ELEMENT_NODE:
2141: case XML_ENTITY_REF_NODE:
2142: case XML_DOCUMENT_NODE:
2143: case XML_NOTATION_NODE:
2144: case XML_HTML_DOCUMENT_NODE: {
2145: return(xmlXPtrNewRange(node, 0, node,
2146: xmlXPtrGetArity(node)));
2147: }
2148: default:
2149: break;
2150: }
2151: return(NULL);
2152: }
2153: }
2154: default:
2155: TODO /* missed one case ??? */
2156: }
2157: return(NULL);
2158: }
2159:
2160: /**
2161: * xmlXPtrRangeInsideFunction:
2162: * @ctxt: the XPointer Parser context
2163: * @nargs: the number of args
2164: *
2165: * Function implementing the range-inside() function 5.4.3
2166: * location-set range-inside(location-set )
2167: *
2168: * The range-inside function returns ranges covering the contents of
2169: * the locations in the argument location-set. For each location x in
2170: * the argument location-set, a range location is added to the result
2171: * location-set. If x is a range location, then x is added to the
2172: * result location-set. If x is not a range location, then x is used
2173: * as the container location of the start and end points of the range
2174: * location to be added; the index of the start point of the range is
2175: * zero; if the end point is a character point then its index is the
2176: * length of the string-value of x, and otherwise is the number of
2177: * location children of x.
2178: *
2179: */
2180: static void
2181: xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2182: int i;
2183: xmlXPathObjectPtr set;
2184: xmlLocationSetPtr oldset;
2185: xmlLocationSetPtr newset;
2186:
2187: CHECK_ARITY(1);
2188: if ((ctxt->value == NULL) ||
2189: ((ctxt->value->type != XPATH_LOCATIONSET) &&
2190: (ctxt->value->type != XPATH_NODESET)))
2191: XP_ERROR(XPATH_INVALID_TYPE)
2192:
2193: set = valuePop(ctxt);
2194: if (set->type == XPATH_NODESET) {
2195: xmlXPathObjectPtr tmp;
2196:
2197: /*
2198: * First convert to a location set
2199: */
2200: tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2201: xmlXPathFreeObject(set);
2202: set = tmp;
2203: }
2204: oldset = (xmlLocationSetPtr) set->user;
2205:
2206: /*
2207: * The loop is to compute the covering range for each item and add it
2208: */
2209: newset = xmlXPtrLocationSetCreate(NULL);
2210: for (i = 0;i < oldset->locNr;i++) {
2211: xmlXPtrLocationSetAdd(newset,
2212: xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
2213: }
2214:
2215: /*
2216: * Save the new value and cleanup
2217: */
2218: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2219: xmlXPathFreeObject(set);
2220: }
2221:
2222: /**
2223: * xmlXPtrRangeToFunction:
2224: * @ctxt: the XPointer Parser context
2225: * @nargs: the number of args
2226: *
2227: * Implement the range-to() XPointer function
2228: */
2229: void
2230: xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2231: xmlXPathObjectPtr range;
2232: const xmlChar *cur;
2233: xmlXPathObjectPtr res, obj;
2234: xmlXPathObjectPtr tmp;
2235: xmlLocationSetPtr newset = NULL;
2236: xmlNodeSetPtr oldset;
2237: int i;
2238:
2239: if (ctxt == NULL) return;
2240: CHECK_ARITY(1);
2241: /*
2242: * Save the expression pointer since we will have to evaluate
2243: * it multiple times. Initialize the new set.
2244: */
2245: CHECK_TYPE(XPATH_NODESET);
2246: obj = valuePop(ctxt);
2247: oldset = obj->nodesetval;
2248: ctxt->context->node = NULL;
2249:
2250: cur = ctxt->cur;
2251: newset = xmlXPtrLocationSetCreate(NULL);
2252:
2253: for (i = 0; i < oldset->nodeNr; i++) {
2254: ctxt->cur = cur;
2255:
2256: /*
2257: * Run the evaluation with a node list made of a single item
2258: * in the nodeset.
2259: */
2260: ctxt->context->node = oldset->nodeTab[i];
2261: tmp = xmlXPathNewNodeSet(ctxt->context->node);
2262: valuePush(ctxt, tmp);
2263:
2264: xmlXPathEvalExpr(ctxt);
2265: CHECK_ERROR;
2266:
2267: /*
2268: * The result of the evaluation need to be tested to
2269: * decided whether the filter succeeded or not
2270: */
2271: res = valuePop(ctxt);
2272: range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
2273: if (range != NULL) {
2274: xmlXPtrLocationSetAdd(newset, range);
2275: }
2276:
2277: /*
2278: * Cleanup
2279: */
2280: if (res != NULL)
2281: xmlXPathFreeObject(res);
2282: if (ctxt->value == tmp) {
2283: res = valuePop(ctxt);
2284: xmlXPathFreeObject(res);
2285: }
2286:
2287: ctxt->context->node = NULL;
2288: }
2289:
2290: /*
2291: * The result is used as the new evaluation set.
2292: */
2293: xmlXPathFreeObject(obj);
2294: ctxt->context->node = NULL;
2295: ctxt->context->contextSize = -1;
2296: ctxt->context->proximityPosition = -1;
2297: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2298: }
2299:
2300: /**
2301: * xmlXPtrAdvanceNode:
2302: * @cur: the node
2303: * @level: incremented/decremented to show level in tree
2304: *
2305: * Advance to the next element or text node in document order
2306: * TODO: add a stack for entering/exiting entities
2307: *
2308: * Returns -1 in case of failure, 0 otherwise
2309: */
2310: xmlNodePtr
2311: xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
2312: next:
2313: if (cur == NULL)
2314: return(NULL);
2315: if (cur->children != NULL) {
2316: cur = cur->children ;
2317: if (level != NULL)
2318: (*level)++;
2319: goto found;
2320: }
2321: skip: /* This label should only be needed if something is wrong! */
2322: if (cur->next != NULL) {
2323: cur = cur->next;
2324: goto found;
2325: }
2326: do {
2327: cur = cur->parent;
2328: if (level != NULL)
2329: (*level)--;
2330: if (cur == NULL) return(NULL);
2331: if (cur->next != NULL) {
2332: cur = cur->next;
2333: goto found;
2334: }
2335: } while (cur != NULL);
2336:
2337: found:
2338: if ((cur->type != XML_ELEMENT_NODE) &&
2339: (cur->type != XML_TEXT_NODE) &&
2340: (cur->type != XML_DOCUMENT_NODE) &&
2341: (cur->type != XML_HTML_DOCUMENT_NODE) &&
2342: (cur->type != XML_CDATA_SECTION_NODE)) {
2343: if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */
2344: TODO
2345: goto skip;
2346: }
2347: goto next;
2348: }
2349: return(cur);
2350: }
2351:
2352: /**
2353: * xmlXPtrAdvanceChar:
2354: * @node: the node
2355: * @indx: the indx
2356: * @bytes: the number of bytes
2357: *
2358: * Advance a point of the associated number of bytes (not UTF8 chars)
2359: *
2360: * Returns -1 in case of failure, 0 otherwise
2361: */
2362: static int
2363: xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) {
2364: xmlNodePtr cur;
2365: int pos;
2366: int len;
2367:
2368: if ((node == NULL) || (indx == NULL))
2369: return(-1);
2370: cur = *node;
2371: if (cur == NULL)
2372: return(-1);
2373: pos = *indx;
2374:
2375: while (bytes >= 0) {
2376: /*
2377: * First position to the beginning of the first text node
2378: * corresponding to this point
2379: */
2380: while ((cur != NULL) &&
2381: ((cur->type == XML_ELEMENT_NODE) ||
2382: (cur->type == XML_DOCUMENT_NODE) ||
2383: (cur->type == XML_HTML_DOCUMENT_NODE))) {
2384: if (pos > 0) {
2385: cur = xmlXPtrGetNthChild(cur, pos);
2386: pos = 0;
2387: } else {
2388: cur = xmlXPtrAdvanceNode(cur, NULL);
2389: pos = 0;
2390: }
2391: }
2392:
2393: if (cur == NULL) {
2394: *node = NULL;
2395: *indx = 0;
2396: return(-1);
2397: }
2398:
2399: /*
2400: * if there is no move needed return the current value.
2401: */
2402: if (pos == 0) pos = 1;
2403: if (bytes == 0) {
2404: *node = cur;
2405: *indx = pos;
2406: return(0);
2407: }
2408: /*
2409: * We should have a text (or cdata) node ...
2410: */
2411: len = 0;
2412: if ((cur->type != XML_ELEMENT_NODE) &&
2413: (cur->content != NULL)) {
2414: len = xmlStrlen(cur->content);
2415: }
2416: if (pos > len) {
2417: /* Strange, the indx in the text node is greater than it's len */
2418: STRANGE
2419: pos = len;
2420: }
2421: if (pos + bytes >= len) {
2422: bytes -= (len - pos);
2423: cur = xmlXPtrAdvanceNode(cur, NULL);
2424: pos = 0;
2425: } else if (pos + bytes < len) {
2426: pos += bytes;
2427: *node = cur;
2428: *indx = pos;
2429: return(0);
2430: }
2431: }
2432: return(-1);
2433: }
2434:
2435: /**
2436: * xmlXPtrMatchString:
2437: * @string: the string to search
2438: * @start: the start textnode
2439: * @startindex: the start index
2440: * @end: the end textnode IN/OUT
2441: * @endindex: the end index IN/OUT
2442: *
2443: * Check whether the document contains @string at the position
2444: * (@start, @startindex) and limited by the (@end, @endindex) point
2445: *
2446: * Returns -1 in case of failure, 0 if not found, 1 if found in which case
2447: * (@start, @startindex) will indicate the position of the beginning
2448: * of the range and (@end, @endindex) will indicate the end
2449: * of the range
2450: */
2451: static int
2452: xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
2453: xmlNodePtr *end, int *endindex) {
2454: xmlNodePtr cur;
2455: int pos; /* 0 based */
2456: int len; /* in bytes */
2457: int stringlen; /* in bytes */
2458: int match;
2459:
2460: if (string == NULL)
2461: return(-1);
2462: if (start == NULL)
2463: return(-1);
2464: if ((end == NULL) || (endindex == NULL))
2465: return(-1);
2466: cur = start;
2467: if (cur == NULL)
2468: return(-1);
2469: pos = startindex - 1;
2470: stringlen = xmlStrlen(string);
2471:
2472: while (stringlen > 0) {
2473: if ((cur == *end) && (pos + stringlen > *endindex))
2474: return(0);
2475:
2476: if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
2477: len = xmlStrlen(cur->content);
2478: if (len >= pos + stringlen) {
2479: match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
2480: if (match) {
2481: #ifdef DEBUG_RANGES
2482: xmlGenericError(xmlGenericErrorContext,
2483: "found range %d bytes at index %d of ->",
2484: stringlen, pos + 1);
2485: xmlDebugDumpString(stdout, cur->content);
2486: xmlGenericError(xmlGenericErrorContext, "\n");
2487: #endif
2488: *end = cur;
2489: *endindex = pos + stringlen;
2490: return(1);
2491: } else {
2492: return(0);
2493: }
2494: } else {
2495: int sub = len - pos;
2496: match = (!xmlStrncmp(&cur->content[pos], string, sub));
2497: if (match) {
2498: #ifdef DEBUG_RANGES
2499: xmlGenericError(xmlGenericErrorContext,
2500: "found subrange %d bytes at index %d of ->",
2501: sub, pos + 1);
2502: xmlDebugDumpString(stdout, cur->content);
2503: xmlGenericError(xmlGenericErrorContext, "\n");
2504: #endif
2505: string = &string[sub];
2506: stringlen -= sub;
2507: } else {
2508: return(0);
2509: }
2510: }
2511: }
2512: cur = xmlXPtrAdvanceNode(cur, NULL);
2513: if (cur == NULL)
2514: return(0);
2515: pos = 0;
2516: }
2517: return(1);
2518: }
2519:
2520: /**
2521: * xmlXPtrSearchString:
2522: * @string: the string to search
2523: * @start: the start textnode IN/OUT
2524: * @startindex: the start index IN/OUT
2525: * @end: the end textnode
2526: * @endindex: the end index
2527: *
2528: * Search the next occurrence of @string within the document content
2529: * until the (@end, @endindex) point is reached
2530: *
2531: * Returns -1 in case of failure, 0 if not found, 1 if found in which case
2532: * (@start, @startindex) will indicate the position of the beginning
2533: * of the range and (@end, @endindex) will indicate the end
2534: * of the range
2535: */
2536: static int
2537: xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
2538: xmlNodePtr *end, int *endindex) {
2539: xmlNodePtr cur;
2540: const xmlChar *str;
2541: int pos; /* 0 based */
2542: int len; /* in bytes */
2543: xmlChar first;
2544:
2545: if (string == NULL)
2546: return(-1);
2547: if ((start == NULL) || (startindex == NULL))
2548: return(-1);
2549: if ((end == NULL) || (endindex == NULL))
2550: return(-1);
2551: cur = *start;
2552: if (cur == NULL)
2553: return(-1);
2554: pos = *startindex - 1;
2555: first = string[0];
2556:
2557: while (cur != NULL) {
2558: if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
2559: len = xmlStrlen(cur->content);
2560: while (pos <= len) {
2561: if (first != 0) {
2562: str = xmlStrchr(&cur->content[pos], first);
2563: if (str != NULL) {
2564: pos = (str - (xmlChar *)(cur->content));
2565: #ifdef DEBUG_RANGES
2566: xmlGenericError(xmlGenericErrorContext,
2567: "found '%c' at index %d of ->",
2568: first, pos + 1);
2569: xmlDebugDumpString(stdout, cur->content);
2570: xmlGenericError(xmlGenericErrorContext, "\n");
2571: #endif
2572: if (xmlXPtrMatchString(string, cur, pos + 1,
2573: end, endindex)) {
2574: *start = cur;
2575: *startindex = pos + 1;
2576: return(1);
2577: }
2578: pos++;
2579: } else {
2580: pos = len + 1;
2581: }
2582: } else {
2583: /*
2584: * An empty string is considered to match before each
2585: * character of the string-value and after the final
2586: * character.
2587: */
2588: #ifdef DEBUG_RANGES
2589: xmlGenericError(xmlGenericErrorContext,
2590: "found '' at index %d of ->",
2591: pos + 1);
2592: xmlDebugDumpString(stdout, cur->content);
2593: xmlGenericError(xmlGenericErrorContext, "\n");
2594: #endif
2595: *start = cur;
2596: *startindex = pos + 1;
2597: *end = cur;
2598: *endindex = pos + 1;
2599: return(1);
2600: }
2601: }
2602: }
2603: if ((cur == *end) && (pos >= *endindex))
2604: return(0);
2605: cur = xmlXPtrAdvanceNode(cur, NULL);
2606: if (cur == NULL)
2607: return(0);
2608: pos = 1;
2609: }
2610: return(0);
2611: }
2612:
2613: /**
2614: * xmlXPtrGetLastChar:
2615: * @node: the node
2616: * @index: the index
2617: *
2618: * Computes the point coordinates of the last char of this point
2619: *
2620: * Returns -1 in case of failure, 0 otherwise
2621: */
2622: static int
2623: xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) {
2624: xmlNodePtr cur;
2625: int pos, len = 0;
2626:
2627: if ((node == NULL) || (indx == NULL))
2628: return(-1);
2629: cur = *node;
2630: pos = *indx;
2631:
2632: if (cur == NULL)
2633: return(-1);
2634:
2635: if ((cur->type == XML_ELEMENT_NODE) ||
2636: (cur->type == XML_DOCUMENT_NODE) ||
2637: (cur->type == XML_HTML_DOCUMENT_NODE)) {
2638: if (pos > 0) {
2639: cur = xmlXPtrGetNthChild(cur, pos);
2640: }
2641: }
2642: while (cur != NULL) {
2643: if (cur->last != NULL)
2644: cur = cur->last;
2645: else if ((cur->type != XML_ELEMENT_NODE) &&
2646: (cur->content != NULL)) {
2647: len = xmlStrlen(cur->content);
2648: break;
2649: } else {
2650: return(-1);
2651: }
2652: }
2653: if (cur == NULL)
2654: return(-1);
2655: *node = cur;
2656: *indx = len;
2657: return(0);
2658: }
2659:
2660: /**
2661: * xmlXPtrGetStartPoint:
2662: * @obj: an range
2663: * @node: the resulting node
2664: * @indx: the resulting index
2665: *
2666: * read the object and return the start point coordinates.
2667: *
2668: * Returns -1 in case of failure, 0 otherwise
2669: */
2670: static int
2671: xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
2672: if ((obj == NULL) || (node == NULL) || (indx == NULL))
2673: return(-1);
2674:
2675: switch (obj->type) {
2676: case XPATH_POINT:
2677: *node = obj->user;
2678: if (obj->index <= 0)
2679: *indx = 0;
2680: else
2681: *indx = obj->index;
2682: return(0);
2683: case XPATH_RANGE:
2684: *node = obj->user;
2685: if (obj->index <= 0)
2686: *indx = 0;
2687: else
2688: *indx = obj->index;
2689: return(0);
2690: default:
2691: break;
2692: }
2693: return(-1);
2694: }
2695:
2696: /**
2697: * xmlXPtrGetEndPoint:
2698: * @obj: an range
2699: * @node: the resulting node
2700: * @indx: the resulting indx
2701: *
2702: * read the object and return the end point coordinates.
2703: *
2704: * Returns -1 in case of failure, 0 otherwise
2705: */
2706: static int
2707: xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
2708: if ((obj == NULL) || (node == NULL) || (indx == NULL))
2709: return(-1);
2710:
2711: switch (obj->type) {
2712: case XPATH_POINT:
2713: *node = obj->user;
2714: if (obj->index <= 0)
2715: *indx = 0;
2716: else
2717: *indx = obj->index;
2718: return(0);
2719: case XPATH_RANGE:
2720: *node = obj->user;
2721: if (obj->index <= 0)
2722: *indx = 0;
2723: else
2724: *indx = obj->index;
2725: return(0);
2726: default:
2727: break;
2728: }
2729: return(-1);
2730: }
2731:
2732: /**
2733: * xmlXPtrStringRangeFunction:
2734: * @ctxt: the XPointer Parser context
2735: * @nargs: the number of args
2736: *
2737: * Function implementing the string-range() function
2738: * range as described in 5.4.2
2739: *
2740: * ------------------------------
2741: * [Definition: For each location in the location-set argument,
2742: * string-range returns a set of string ranges, a set of substrings in a
2743: * string. Specifically, the string-value of the location is searched for
2744: * substrings that match the string argument, and the resulting location-set
2745: * will contain a range location for each non-overlapping match.]
2746: * An empty string is considered to match before each character of the
2747: * string-value and after the final character. Whitespace in a string
2748: * is matched literally, with no normalization except that provided by
2749: * XML for line ends. The third argument gives the position of the first
2750: * character to be in the resulting range, relative to the start of the
2751: * match. The default value is 1, which makes the range start immediately
2752: * before the first character of the matched string. The fourth argument
2753: * gives the number of characters in the range; the default is that the
2754: * range extends to the end of the matched string.
2755: *
2756: * Element boundaries, as well as entire embedded nodes such as processing
2757: * instructions and comments, are ignored as defined in [XPath].
2758: *
2759: * If the string in the second argument is not found in the string-value
2760: * of the location, or if a value in the third or fourth argument indicates
2761: * a string that is beyond the beginning or end of the document, the
2762: * expression fails.
2763: *
2764: * The points of the range-locations in the returned location-set will
2765: * all be character points.
2766: * ------------------------------
2767: */
2768: static void
2769: xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2770: int i, startindex, endindex = 0, fendindex;
2771: xmlNodePtr start, end = 0, fend;
2772: xmlXPathObjectPtr set;
2773: xmlLocationSetPtr oldset;
2774: xmlLocationSetPtr newset;
2775: xmlXPathObjectPtr string;
2776: xmlXPathObjectPtr position = NULL;
2777: xmlXPathObjectPtr number = NULL;
2778: int found, pos = 0, num = 0;
2779:
2780: /*
2781: * Grab the arguments
2782: */
2783: if ((nargs < 2) || (nargs > 4))
2784: XP_ERROR(XPATH_INVALID_ARITY);
2785:
2786: if (nargs >= 4) {
2787: CHECK_TYPE(XPATH_NUMBER);
2788: number = valuePop(ctxt);
2789: if (number != NULL)
2790: num = (int) number->floatval;
2791: }
2792: if (nargs >= 3) {
2793: CHECK_TYPE(XPATH_NUMBER);
2794: position = valuePop(ctxt);
2795: if (position != NULL)
2796: pos = (int) position->floatval;
2797: }
2798: CHECK_TYPE(XPATH_STRING);
2799: string = valuePop(ctxt);
2800: if ((ctxt->value == NULL) ||
2801: ((ctxt->value->type != XPATH_LOCATIONSET) &&
2802: (ctxt->value->type != XPATH_NODESET)))
2803: XP_ERROR(XPATH_INVALID_TYPE)
2804:
2805: set = valuePop(ctxt);
2806: newset = xmlXPtrLocationSetCreate(NULL);
2807: if (set->nodesetval == NULL) {
2808: goto error;
2809: }
2810: if (set->type == XPATH_NODESET) {
2811: xmlXPathObjectPtr tmp;
2812:
2813: /*
2814: * First convert to a location set
2815: */
2816: tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2817: xmlXPathFreeObject(set);
2818: set = tmp;
2819: }
2820: oldset = (xmlLocationSetPtr) set->user;
2821:
2822: /*
2823: * The loop is to search for each element in the location set
2824: * the list of location set corresponding to that search
2825: */
2826: for (i = 0;i < oldset->locNr;i++) {
2827: #ifdef DEBUG_RANGES
2828: xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0);
2829: #endif
2830:
2831: xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
2832: xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
2833: xmlXPtrAdvanceChar(&start, &startindex, 0);
2834: xmlXPtrGetLastChar(&end, &endindex);
2835:
2836: #ifdef DEBUG_RANGES
2837: xmlGenericError(xmlGenericErrorContext,
2838: "from index %d of ->", startindex);
2839: xmlDebugDumpString(stdout, start->content);
2840: xmlGenericError(xmlGenericErrorContext, "\n");
2841: xmlGenericError(xmlGenericErrorContext,
2842: "to index %d of ->", endindex);
2843: xmlDebugDumpString(stdout, end->content);
2844: xmlGenericError(xmlGenericErrorContext, "\n");
2845: #endif
2846: do {
2847: fend = end;
2848: fendindex = endindex;
2849: found = xmlXPtrSearchString(string->stringval, &start, &startindex,
2850: &fend, &fendindex);
2851: if (found == 1) {
2852: if (position == NULL) {
2853: xmlXPtrLocationSetAdd(newset,
2854: xmlXPtrNewRange(start, startindex, fend, fendindex));
2855: } else if (xmlXPtrAdvanceChar(&start, &startindex,
2856: pos - 1) == 0) {
2857: if ((number != NULL) && (num > 0)) {
2858: int rindx;
2859: xmlNodePtr rend;
2860: rend = start;
2861: rindx = startindex - 1;
2862: if (xmlXPtrAdvanceChar(&rend, &rindx,
2863: num) == 0) {
2864: xmlXPtrLocationSetAdd(newset,
2865: xmlXPtrNewRange(start, startindex,
2866: rend, rindx));
2867: }
2868: } else if ((number != NULL) && (num <= 0)) {
2869: xmlXPtrLocationSetAdd(newset,
2870: xmlXPtrNewRange(start, startindex,
2871: start, startindex));
2872: } else {
2873: xmlXPtrLocationSetAdd(newset,
2874: xmlXPtrNewRange(start, startindex,
2875: fend, fendindex));
2876: }
2877: }
2878: start = fend;
2879: startindex = fendindex;
2880: if (string->stringval[0] == 0)
2881: startindex++;
2882: }
2883: } while (found == 1);
2884: }
2885:
2886: /*
2887: * Save the new value and cleanup
2888: */
2889: error:
2890: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2891: xmlXPathFreeObject(set);
2892: xmlXPathFreeObject(string);
2893: if (position) xmlXPathFreeObject(position);
2894: if (number) xmlXPathFreeObject(number);
2895: }
2896:
2897: /**
2898: * xmlXPtrEvalRangePredicate:
2899: * @ctxt: the XPointer Parser context
2900: *
2901: * [8] Predicate ::= '[' PredicateExpr ']'
2902: * [9] PredicateExpr ::= Expr
2903: *
2904: * Evaluate a predicate as in xmlXPathEvalPredicate() but for
2905: * a Location Set instead of a node set
2906: */
2907: void
2908: xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) {
2909: const xmlChar *cur;
2910: xmlXPathObjectPtr res;
2911: xmlXPathObjectPtr obj, tmp;
2912: xmlLocationSetPtr newset = NULL;
2913: xmlLocationSetPtr oldset;
2914: int i;
2915:
2916: if (ctxt == NULL) return;
2917:
2918: SKIP_BLANKS;
2919: if (CUR != '[') {
2920: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
2921: }
2922: NEXT;
2923: SKIP_BLANKS;
2924:
2925: /*
2926: * Extract the old set, and then evaluate the result of the
2927: * expression for all the element in the set. use it to grow
2928: * up a new set.
2929: */
2930: CHECK_TYPE(XPATH_LOCATIONSET);
2931: obj = valuePop(ctxt);
2932: oldset = obj->user;
2933: ctxt->context->node = NULL;
2934:
2935: if ((oldset == NULL) || (oldset->locNr == 0)) {
2936: ctxt->context->contextSize = 0;
2937: ctxt->context->proximityPosition = 0;
2938: xmlXPathEvalExpr(ctxt);
2939: res = valuePop(ctxt);
2940: if (res != NULL)
2941: xmlXPathFreeObject(res);
2942: valuePush(ctxt, obj);
2943: CHECK_ERROR;
2944: } else {
2945: /*
2946: * Save the expression pointer since we will have to evaluate
2947: * it multiple times. Initialize the new set.
2948: */
2949: cur = ctxt->cur;
2950: newset = xmlXPtrLocationSetCreate(NULL);
2951:
2952: for (i = 0; i < oldset->locNr; i++) {
2953: ctxt->cur = cur;
2954:
2955: /*
2956: * Run the evaluation with a node list made of a single item
2957: * in the nodeset.
2958: */
2959: ctxt->context->node = oldset->locTab[i]->user;
2960: tmp = xmlXPathNewNodeSet(ctxt->context->node);
2961: valuePush(ctxt, tmp);
2962: ctxt->context->contextSize = oldset->locNr;
2963: ctxt->context->proximityPosition = i + 1;
2964:
2965: xmlXPathEvalExpr(ctxt);
2966: CHECK_ERROR;
2967:
2968: /*
2969: * The result of the evaluation need to be tested to
2970: * decided whether the filter succeeded or not
2971: */
2972: res = valuePop(ctxt);
2973: if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
2974: xmlXPtrLocationSetAdd(newset,
2975: xmlXPathObjectCopy(oldset->locTab[i]));
2976: }
2977:
2978: /*
2979: * Cleanup
2980: */
2981: if (res != NULL)
2982: xmlXPathFreeObject(res);
2983: if (ctxt->value == tmp) {
2984: res = valuePop(ctxt);
2985: xmlXPathFreeObject(res);
2986: }
2987:
2988: ctxt->context->node = NULL;
2989: }
2990:
2991: /*
2992: * The result is used as the new evaluation set.
2993: */
2994: xmlXPathFreeObject(obj);
2995: ctxt->context->node = NULL;
2996: ctxt->context->contextSize = -1;
2997: ctxt->context->proximityPosition = -1;
2998: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2999: }
3000: if (CUR != ']') {
3001: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
3002: }
3003:
3004: NEXT;
3005: SKIP_BLANKS;
3006: }
3007:
3008: #define bottom_xpointer
3009: #include "elfgcchack.h"
3010: #endif
3011:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>