Annotation of embedaddon/libxml2/xpointer.c, revision 1.1.1.3
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
1.1.1.3 ! misho 10: * http://www.w3.org/TR/2002/PR-xptr-element-20021113/
1.1 misho 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:
1.1.1.3 ! misho 50: #define TODO \
1.1 misho 51: xmlGenericError(xmlGenericErrorContext, \
52: "Unimplemented block at %s:%d\n", \
53: __FILE__, __LINE__);
54:
1.1.1.3 ! misho 55: #define STRANGE \
1.1 misho 56: xmlGenericError(xmlGenericErrorContext, \
57: "Internal error at %s:%d\n", \
58: __FILE__, __LINE__);
59:
60: /************************************************************************
61: * *
1.1.1.3 ! misho 62: * Some factorized error routines *
1.1 misho 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;
1.1.1.3 ! misho 137: if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
1.1 misho 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;
1.1.1.3 ! misho 160: if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
1.1 misho 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;
1.1.1.3 ! misho 182: if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
1.1 misho 183: return(cur);
184: cur = cur->children;
185: for (i = 0;i <= no;cur = cur->next) {
1.1.1.3 ! misho 186: if (cur == NULL)
1.1 misho 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: /*
1.1.1.3 ! misho 556: * Empty set ...
1.1 misho 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
1.1.1.3 ! misho 734: xmlGenericError(xmlGenericErrorContext,
1.1 misho 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:
1.1.1.3 ! misho 906: #define SKIP_BLANKS \
1.1 misho 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
1.1.1.3 ! misho 948: *
1.1 misho 949: * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
950: * | Scheme '(' SchemeSpecificExpr ')'
951: *
952: * Scheme ::= NCName - 'xpointer' [VC: Non-XPointer schemes]
953: *
954: * SchemeSpecificExpr ::= StringWithBalancedParens
955: *
1.1.1.3 ! misho 956: * StringWithBalancedParens ::=
1.1 misho 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.
1.1.1.3 ! misho 974: *
1.1 misho 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: } else if (CUR == '(') {
1011: level++;
1012: } else if (CUR == '^') {
1.1.1.2 misho 1013: if ((NXT(1) == ')') || (NXT(1) == '(') || (NXT(1) == '^')) {
1014: NEXT;
1015: }
1.1 misho 1016: }
1.1.1.2 misho 1017: *cur++ = CUR;
1.1 misho 1018: NEXT;
1019: }
1020: *cur = 0;
1021:
1022: if ((level != 0) && (CUR == 0)) {
1023: xmlFree(buffer);
1024: XP_ERROR(XPTR_SYNTAX_ERROR);
1025: }
1026:
1027: if (xmlStrEqual(name, (xmlChar *) "xpointer")) {
1028: const xmlChar *left = CUR_PTR;
1029:
1030: CUR_PTR = buffer;
1031: /*
1032: * To evaluate an xpointer scheme element (4.3) we need:
1033: * context initialized to the root
1034: * context position initalized to 1
1035: * context size initialized to 1
1036: */
1037: ctxt->context->node = (xmlNodePtr)ctxt->context->doc;
1038: ctxt->context->proximityPosition = 1;
1039: ctxt->context->contextSize = 1;
1040: xmlXPathEvalExpr(ctxt);
1041: CUR_PTR=left;
1042: } else if (xmlStrEqual(name, (xmlChar *) "element")) {
1043: const xmlChar *left = CUR_PTR;
1044: xmlChar *name2;
1045:
1046: CUR_PTR = buffer;
1047: if (buffer[0] == '/') {
1048: xmlXPathRoot(ctxt);
1049: xmlXPtrEvalChildSeq(ctxt, NULL);
1050: } else {
1051: name2 = xmlXPathParseName(ctxt);
1052: if (name2 == NULL) {
1053: CUR_PTR = left;
1054: xmlFree(buffer);
1055: XP_ERROR(XPATH_EXPR_ERROR);
1056: }
1057: xmlXPtrEvalChildSeq(ctxt, name2);
1058: }
1059: CUR_PTR = left;
1060: #ifdef XPTR_XMLNS_SCHEME
1061: } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
1062: const xmlChar *left = CUR_PTR;
1063: xmlChar *prefix;
1064: xmlChar *URI;
1065: xmlURIPtr value;
1066:
1067: CUR_PTR = buffer;
1068: prefix = xmlXPathParseNCName(ctxt);
1069: if (prefix == NULL) {
1070: xmlFree(buffer);
1071: xmlFree(name);
1072: XP_ERROR(XPTR_SYNTAX_ERROR);
1073: }
1074: SKIP_BLANKS;
1075: if (CUR != '=') {
1076: xmlFree(prefix);
1077: xmlFree(buffer);
1078: xmlFree(name);
1079: XP_ERROR(XPTR_SYNTAX_ERROR);
1080: }
1081: NEXT;
1082: SKIP_BLANKS;
1083: /* @@ check escaping in the XPointer WD */
1084:
1085: value = xmlParseURI((const char *)ctxt->cur);
1086: if (value == NULL) {
1087: xmlFree(prefix);
1088: xmlFree(buffer);
1089: xmlFree(name);
1090: XP_ERROR(XPTR_SYNTAX_ERROR);
1091: }
1092: URI = xmlSaveUri(value);
1093: xmlFreeURI(value);
1094: if (URI == NULL) {
1095: xmlFree(prefix);
1096: xmlFree(buffer);
1097: xmlFree(name);
1098: XP_ERROR(XPATH_MEMORY_ERROR);
1099: }
1.1.1.3 ! misho 1100:
1.1 misho 1101: xmlXPathRegisterNs(ctxt->context, prefix, URI);
1102: CUR_PTR = left;
1103: xmlFree(URI);
1104: xmlFree(prefix);
1105: #endif /* XPTR_XMLNS_SCHEME */
1106: } else {
1107: xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME,
1108: "unsupported scheme '%s'\n", name);
1109: }
1110: xmlFree(buffer);
1111: xmlFree(name);
1112: }
1113:
1114: /**
1115: * xmlXPtrEvalFullXPtr:
1116: * @ctxt: the XPointer Parser context
1117: * @name: the preparsed Scheme for the first XPtrPart
1118: *
1119: * FullXPtr ::= XPtrPart (S? XPtrPart)*
1120: *
1121: * As the specs says:
1122: * -----------
1123: * When multiple XPtrParts are provided, they must be evaluated in
1124: * left-to-right order. If evaluation of one part fails, the nexti
1125: * is evaluated. The following conditions cause XPointer part failure:
1126: *
1127: * - An unknown scheme
1128: * - A scheme that does not locate any sub-resource present in the resource
1129: * - A scheme that is not applicable to the media type of the resource
1130: *
1131: * The XPointer application must consume a failed XPointer part and
1132: * attempt to evaluate the next one, if any. The result of the first
1133: * XPointer part whose evaluation succeeds is taken to be the fragment
1134: * located by the XPointer as a whole. If all the parts fail, the result
1135: * for the XPointer as a whole is a sub-resource error.
1136: * -----------
1137: *
1138: * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
1139: * expressions or other schemes.
1140: */
1141: static void
1142: xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
1143: if (name == NULL)
1144: name = xmlXPathParseName(ctxt);
1145: if (name == NULL)
1146: XP_ERROR(XPATH_EXPR_ERROR);
1147: while (name != NULL) {
1148: ctxt->error = XPATH_EXPRESSION_OK;
1149: xmlXPtrEvalXPtrPart(ctxt, name);
1150:
1151: /* in case of syntax error, break here */
1152: if ((ctxt->error != XPATH_EXPRESSION_OK) &&
1153: (ctxt->error != XML_XPTR_UNKNOWN_SCHEME))
1154: return;
1155:
1156: /*
1157: * If the returned value is a non-empty nodeset
1158: * or location set, return here.
1159: */
1160: if (ctxt->value != NULL) {
1161: xmlXPathObjectPtr obj = ctxt->value;
1162:
1163: switch (obj->type) {
1164: case XPATH_LOCATIONSET: {
1165: xmlLocationSetPtr loc = ctxt->value->user;
1166: if ((loc != NULL) && (loc->locNr > 0))
1167: return;
1168: break;
1169: }
1170: case XPATH_NODESET: {
1171: xmlNodeSetPtr loc = ctxt->value->nodesetval;
1172: if ((loc != NULL) && (loc->nodeNr > 0))
1173: return;
1174: break;
1175: }
1176: default:
1177: break;
1178: }
1179:
1180: /*
1181: * Evaluating to improper values is equivalent to
1182: * a sub-resource error, clean-up the stack
1183: */
1184: do {
1185: obj = valuePop(ctxt);
1186: if (obj != NULL) {
1187: xmlXPathFreeObject(obj);
1188: }
1189: } while (obj != NULL);
1190: }
1191:
1192: /*
1193: * Is there another XPointer part.
1194: */
1195: SKIP_BLANKS;
1196: name = xmlXPathParseName(ctxt);
1197: }
1198: }
1199:
1200: /**
1201: * xmlXPtrEvalChildSeq:
1202: * @ctxt: the XPointer Parser context
1203: * @name: a possible ID name of the child sequence
1204: *
1205: * ChildSeq ::= '/1' ('/' [0-9]*)*
1206: * | Name ('/' [0-9]*)+
1207: *
1208: * Parse and evaluate a Child Sequence. This routine also handle the
1209: * case of a Bare Name used to get a document ID.
1210: */
1211: static void
1212: xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
1213: /*
1214: * XPointer don't allow by syntax to address in mutirooted trees
1215: * this might prove useful in some cases, warn about it.
1216: */
1217: if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
1218: xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START,
1219: "warning: ChildSeq not starting by /1\n", NULL);
1220: }
1221:
1222: if (name != NULL) {
1223: valuePush(ctxt, xmlXPathNewString(name));
1224: xmlFree(name);
1225: xmlXPathIdFunction(ctxt, 1);
1226: CHECK_ERROR;
1227: }
1228:
1229: while (CUR == '/') {
1230: int child = 0;
1231: NEXT;
1.1.1.3 ! misho 1232:
1.1 misho 1233: while ((CUR >= '0') && (CUR <= '9')) {
1234: child = child * 10 + (CUR - '0');
1235: NEXT;
1236: }
1237: xmlXPtrGetChildNo(ctxt, child);
1238: }
1239: }
1240:
1241:
1242: /**
1243: * xmlXPtrEvalXPointer:
1244: * @ctxt: the XPointer Parser context
1245: *
1246: * XPointer ::= Name
1247: * | ChildSeq
1248: * | FullXPtr
1249: *
1250: * Parse and evaluate an XPointer
1251: */
1252: static void
1253: xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
1254: if (ctxt->valueTab == NULL) {
1255: /* Allocate the value stack */
1.1.1.3 ! misho 1256: ctxt->valueTab = (xmlXPathObjectPtr *)
1.1 misho 1257: xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
1258: if (ctxt->valueTab == NULL) {
1259: xmlXPtrErrMemory("allocating evaluation context");
1260: return;
1261: }
1262: ctxt->valueNr = 0;
1263: ctxt->valueMax = 10;
1264: ctxt->value = NULL;
1.1.1.2 misho 1265: ctxt->valueFrame = 0;
1.1 misho 1266: }
1267: SKIP_BLANKS;
1268: if (CUR == '/') {
1269: xmlXPathRoot(ctxt);
1270: xmlXPtrEvalChildSeq(ctxt, NULL);
1271: } else {
1272: xmlChar *name;
1273:
1274: name = xmlXPathParseName(ctxt);
1275: if (name == NULL)
1276: XP_ERROR(XPATH_EXPR_ERROR);
1277: if (CUR == '(') {
1278: xmlXPtrEvalFullXPtr(ctxt, name);
1279: /* Short evaluation */
1280: return;
1281: } else {
1282: /* this handle both Bare Names and Child Sequences */
1283: xmlXPtrEvalChildSeq(ctxt, name);
1284: }
1285: }
1286: SKIP_BLANKS;
1287: if (CUR != 0)
1288: XP_ERROR(XPATH_EXPR_ERROR);
1289: }
1290:
1291:
1292: /************************************************************************
1293: * *
1294: * General routines *
1295: * *
1296: ************************************************************************/
1297:
1298: static
1299: void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
1300: static
1301: void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1302: static
1303: void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1304: static
1305: void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
1306: static
1307: void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
1308: static
1309: void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
1310: static
1311: void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
1312:
1313: /**
1314: * xmlXPtrNewContext:
1315: * @doc: the XML document
1316: * @here: the node that directly contains the XPointer being evaluated or NULL
1317: * @origin: the element from which a user or program initiated traversal of
1318: * the link, or NULL.
1319: *
1320: * Create a new XPointer context
1321: *
1322: * Returns the xmlXPathContext just allocated.
1323: */
1324: xmlXPathContextPtr
1325: xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
1326: xmlXPathContextPtr ret;
1327:
1328: ret = xmlXPathNewContext(doc);
1329: if (ret == NULL)
1330: return(ret);
1331: ret->xptr = 1;
1332: ret->here = here;
1333: ret->origin = origin;
1334:
1335: xmlXPathRegisterFunc(ret, (xmlChar *)"range-to",
1336: xmlXPtrRangeToFunction);
1337: xmlXPathRegisterFunc(ret, (xmlChar *)"range",
1338: xmlXPtrRangeFunction);
1339: xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
1340: xmlXPtrRangeInsideFunction);
1341: xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
1342: xmlXPtrStringRangeFunction);
1343: xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
1344: xmlXPtrStartPointFunction);
1345: xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
1346: xmlXPtrEndPointFunction);
1347: xmlXPathRegisterFunc(ret, (xmlChar *)"here",
1348: xmlXPtrHereFunction);
1349: xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
1350: xmlXPtrOriginFunction);
1351:
1352: return(ret);
1353: }
1354:
1355: /**
1356: * xmlXPtrEval:
1357: * @str: the XPointer expression
1358: * @ctx: the XPointer context
1359: *
1360: * Evaluate the XPath Location Path in the given context.
1361: *
1362: * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
1363: * the caller has to free the object.
1364: */
1365: xmlXPathObjectPtr
1366: xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
1367: xmlXPathParserContextPtr ctxt;
1368: xmlXPathObjectPtr res = NULL, tmp;
1369: xmlXPathObjectPtr init = NULL;
1370: int stack = 0;
1371:
1372: xmlXPathInit();
1373:
1374: if ((ctx == NULL) || (str == NULL))
1375: return(NULL);
1376:
1377: ctxt = xmlXPathNewParserContext(str, ctx);
1378: ctxt->xptr = 1;
1379: xmlXPtrEvalXPointer(ctxt);
1380:
1381: if ((ctxt->value != NULL) &&
1382: (ctxt->value->type != XPATH_NODESET) &&
1383: (ctxt->value->type != XPATH_LOCATIONSET)) {
1384: xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED,
1385: "xmlXPtrEval: evaluation failed to return a node set\n",
1386: NULL);
1387: } else {
1388: res = valuePop(ctxt);
1389: }
1390:
1391: do {
1392: tmp = valuePop(ctxt);
1393: if (tmp != NULL) {
1394: if (tmp != init) {
1395: if (tmp->type == XPATH_NODESET) {
1396: /*
1397: * Evaluation may push a root nodeset which is unused
1398: */
1.1.1.3 ! misho 1399: xmlNodeSetPtr set;
1.1 misho 1400: set = tmp->nodesetval;
1401: if ((set->nodeNr != 1) ||
1402: (set->nodeTab[0] != (xmlNodePtr) ctx->doc))
1403: stack++;
1404: } else
1.1.1.3 ! misho 1405: stack++;
1.1 misho 1406: }
1407: xmlXPathFreeObject(tmp);
1408: }
1409: } while (tmp != NULL);
1410: if (stack != 0) {
1411: xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS,
1412: "xmlXPtrEval: object(s) left on the eval stack\n",
1413: NULL);
1414: }
1415: if (ctxt->error != XPATH_EXPRESSION_OK) {
1416: xmlXPathFreeObject(res);
1417: res = NULL;
1418: }
1.1.1.3 ! misho 1419:
1.1 misho 1420: xmlXPathFreeParserContext(ctxt);
1421: return(res);
1422: }
1423:
1424: /**
1425: * xmlXPtrBuildRangeNodeList:
1426: * @range: a range object
1427: *
1428: * Build a node list tree copy of the range
1429: *
1430: * Returns an xmlNodePtr list or NULL.
1431: * the caller has to free the node tree.
1432: */
1433: static xmlNodePtr
1434: xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) {
1435: /* pointers to generated nodes */
1436: xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
1437: /* pointers to traversal nodes */
1438: xmlNodePtr start, cur, end;
1439: int index1, index2;
1440:
1441: if (range == NULL)
1442: return(NULL);
1443: if (range->type != XPATH_RANGE)
1444: return(NULL);
1445: start = (xmlNodePtr) range->user;
1446:
1.1.1.3 ! misho 1447: if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
1.1 misho 1448: return(NULL);
1449: end = range->user2;
1450: if (end == NULL)
1451: return(xmlCopyNode(start, 1));
1.1.1.3 ! misho 1452: if (end->type == XML_NAMESPACE_DECL)
! 1453: return(NULL);
1.1 misho 1454:
1455: cur = start;
1456: index1 = range->index;
1457: index2 = range->index2;
1458: while (cur != NULL) {
1459: if (cur == end) {
1460: if (cur->type == XML_TEXT_NODE) {
1461: const xmlChar *content = cur->content;
1462: int len;
1463:
1464: if (content == NULL) {
1465: tmp = xmlNewTextLen(NULL, 0);
1466: } else {
1467: len = index2;
1468: if ((cur == start) && (index1 > 1)) {
1469: content += (index1 - 1);
1470: len -= (index1 - 1);
1471: index1 = 0;
1472: } else {
1473: len = index2;
1474: }
1475: tmp = xmlNewTextLen(content, len);
1476: }
1477: /* single sub text node selection */
1478: if (list == NULL)
1479: return(tmp);
1480: /* prune and return full set */
1481: if (last != NULL)
1482: xmlAddNextSibling(last, tmp);
1.1.1.3 ! misho 1483: else
1.1 misho 1484: xmlAddChild(parent, tmp);
1485: return(list);
1486: } else {
1487: tmp = xmlCopyNode(cur, 0);
1488: if (list == NULL)
1489: list = tmp;
1490: else {
1491: if (last != NULL)
1492: xmlAddNextSibling(last, tmp);
1493: else
1494: xmlAddChild(parent, tmp);
1495: }
1496: last = NULL;
1497: parent = tmp;
1498:
1499: if (index2 > 1) {
1500: end = xmlXPtrGetNthChild(cur, index2 - 1);
1501: index2 = 0;
1502: }
1503: if ((cur == start) && (index1 > 1)) {
1504: cur = xmlXPtrGetNthChild(cur, index1 - 1);
1505: index1 = 0;
1506: } else {
1507: cur = cur->children;
1508: }
1509: /*
1510: * Now gather the remaining nodes from cur to end
1511: */
1512: continue; /* while */
1513: }
1514: } else if ((cur == start) &&
1515: (list == NULL) /* looks superfluous but ... */ ) {
1516: if ((cur->type == XML_TEXT_NODE) ||
1517: (cur->type == XML_CDATA_SECTION_NODE)) {
1518: const xmlChar *content = cur->content;
1519:
1520: if (content == NULL) {
1521: tmp = xmlNewTextLen(NULL, 0);
1522: } else {
1523: if (index1 > 1) {
1524: content += (index1 - 1);
1525: }
1526: tmp = xmlNewText(content);
1527: }
1528: last = list = tmp;
1529: } else {
1530: if ((cur == start) && (index1 > 1)) {
1531: tmp = xmlCopyNode(cur, 0);
1532: list = tmp;
1533: parent = tmp;
1534: last = NULL;
1535: cur = xmlXPtrGetNthChild(cur, index1 - 1);
1536: index1 = 0;
1537: /*
1538: * Now gather the remaining nodes from cur to end
1539: */
1540: continue; /* while */
1541: }
1542: tmp = xmlCopyNode(cur, 1);
1543: list = tmp;
1544: parent = NULL;
1545: last = tmp;
1546: }
1547: } else {
1548: tmp = NULL;
1549: switch (cur->type) {
1550: case XML_DTD_NODE:
1551: case XML_ELEMENT_DECL:
1552: case XML_ATTRIBUTE_DECL:
1553: case XML_ENTITY_NODE:
1554: /* Do not copy DTD informations */
1555: break;
1556: case XML_ENTITY_DECL:
1557: TODO /* handle crossing entities -> stack needed */
1558: break;
1559: case XML_XINCLUDE_START:
1560: case XML_XINCLUDE_END:
1561: /* don't consider it part of the tree content */
1562: break;
1563: case XML_ATTRIBUTE_NODE:
1564: /* Humm, should not happen ! */
1565: STRANGE
1566: break;
1567: default:
1568: tmp = xmlCopyNode(cur, 1);
1569: break;
1570: }
1571: if (tmp != NULL) {
1572: if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
1573: STRANGE
1574: return(NULL);
1575: }
1576: if (last != NULL)
1577: xmlAddNextSibling(last, tmp);
1578: else {
1579: xmlAddChild(parent, tmp);
1580: last = tmp;
1581: }
1582: }
1583: }
1584: /*
1585: * Skip to next node in document order
1586: */
1587: if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
1588: STRANGE
1589: return(NULL);
1590: }
1591: cur = xmlXPtrAdvanceNode(cur, NULL);
1592: }
1593: return(list);
1594: }
1595:
1596: /**
1597: * xmlXPtrBuildNodeList:
1598: * @obj: the XPointer result from the evaluation.
1599: *
1600: * Build a node list tree copy of the XPointer result.
1601: * This will drop Attributes and Namespace declarations.
1602: *
1603: * Returns an xmlNodePtr list or NULL.
1604: * the caller has to free the node tree.
1605: */
1606: xmlNodePtr
1607: xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) {
1608: xmlNodePtr list = NULL, last = NULL;
1609: int i;
1610:
1611: if (obj == NULL)
1612: return(NULL);
1613: switch (obj->type) {
1614: case XPATH_NODESET: {
1615: xmlNodeSetPtr set = obj->nodesetval;
1616: if (set == NULL)
1617: return(NULL);
1618: for (i = 0;i < set->nodeNr;i++) {
1619: if (set->nodeTab[i] == NULL)
1620: continue;
1621: switch (set->nodeTab[i]->type) {
1622: case XML_TEXT_NODE:
1623: case XML_CDATA_SECTION_NODE:
1624: case XML_ELEMENT_NODE:
1625: case XML_ENTITY_REF_NODE:
1626: case XML_ENTITY_NODE:
1627: case XML_PI_NODE:
1628: case XML_COMMENT_NODE:
1629: case XML_DOCUMENT_NODE:
1630: case XML_HTML_DOCUMENT_NODE:
1631: #ifdef LIBXML_DOCB_ENABLED
1632: case XML_DOCB_DOCUMENT_NODE:
1633: #endif
1634: case XML_XINCLUDE_START:
1635: case XML_XINCLUDE_END:
1636: break;
1637: case XML_ATTRIBUTE_NODE:
1638: case XML_NAMESPACE_DECL:
1639: case XML_DOCUMENT_TYPE_NODE:
1640: case XML_DOCUMENT_FRAG_NODE:
1641: case XML_NOTATION_NODE:
1642: case XML_DTD_NODE:
1643: case XML_ELEMENT_DECL:
1644: case XML_ATTRIBUTE_DECL:
1645: case XML_ENTITY_DECL:
1646: continue; /* for */
1647: }
1648: if (last == NULL)
1649: list = last = xmlCopyNode(set->nodeTab[i], 1);
1650: else {
1651: xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1));
1652: if (last->next != NULL)
1653: last = last->next;
1654: }
1655: }
1656: break;
1657: }
1658: case XPATH_LOCATIONSET: {
1659: xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1660: if (set == NULL)
1661: return(NULL);
1662: for (i = 0;i < set->locNr;i++) {
1663: if (last == NULL)
1664: list = last = xmlXPtrBuildNodeList(set->locTab[i]);
1665: else
1666: xmlAddNextSibling(last,
1667: xmlXPtrBuildNodeList(set->locTab[i]));
1668: if (last != NULL) {
1669: while (last->next != NULL)
1670: last = last->next;
1671: }
1672: }
1673: break;
1674: }
1675: case XPATH_RANGE:
1676: return(xmlXPtrBuildRangeNodeList(obj));
1677: case XPATH_POINT:
1678: return(xmlCopyNode(obj->user, 0));
1679: default:
1680: break;
1681: }
1682: return(list);
1683: }
1684:
1685: /************************************************************************
1686: * *
1687: * XPointer functions *
1688: * *
1689: ************************************************************************/
1690:
1691: /**
1692: * xmlXPtrNbLocChildren:
1693: * @node: an xmlNodePtr
1694: *
1695: * Count the number of location children of @node or the length of the
1696: * string value in case of text/PI/Comments nodes
1697: *
1698: * Returns the number of location children
1699: */
1700: static int
1701: xmlXPtrNbLocChildren(xmlNodePtr node) {
1702: int ret = 0;
1703: if (node == NULL)
1704: return(-1);
1705: switch (node->type) {
1706: case XML_HTML_DOCUMENT_NODE:
1707: case XML_DOCUMENT_NODE:
1708: case XML_ELEMENT_NODE:
1709: node = node->children;
1710: while (node != NULL) {
1711: if (node->type == XML_ELEMENT_NODE)
1712: ret++;
1713: node = node->next;
1714: }
1715: break;
1716: case XML_ATTRIBUTE_NODE:
1717: return(-1);
1718:
1719: case XML_PI_NODE:
1720: case XML_COMMENT_NODE:
1721: case XML_TEXT_NODE:
1722: case XML_CDATA_SECTION_NODE:
1723: case XML_ENTITY_REF_NODE:
1724: ret = xmlStrlen(node->content);
1725: break;
1726: default:
1727: return(-1);
1728: }
1729: return(ret);
1730: }
1731:
1732: /**
1733: * xmlXPtrHereFunction:
1734: * @ctxt: the XPointer Parser context
1735: * @nargs: the number of args
1736: *
1.1.1.3 ! misho 1737: * Function implementing here() operation
1.1 misho 1738: * as described in 5.4.3
1739: */
1740: static void
1741: xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1742: CHECK_ARITY(0);
1743:
1744: if (ctxt->context->here == NULL)
1745: XP_ERROR(XPTR_SYNTAX_ERROR);
1.1.1.3 ! misho 1746:
1.1 misho 1747: valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL));
1748: }
1749:
1750: /**
1751: * xmlXPtrOriginFunction:
1752: * @ctxt: the XPointer Parser context
1753: * @nargs: the number of args
1754: *
1.1.1.3 ! misho 1755: * Function implementing origin() operation
1.1 misho 1756: * as described in 5.4.3
1757: */
1758: static void
1759: xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1760: CHECK_ARITY(0);
1761:
1762: if (ctxt->context->origin == NULL)
1763: XP_ERROR(XPTR_SYNTAX_ERROR);
1.1.1.3 ! misho 1764:
1.1 misho 1765: valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL));
1766: }
1767:
1768: /**
1769: * xmlXPtrStartPointFunction:
1770: * @ctxt: the XPointer Parser context
1771: * @nargs: the number of args
1772: *
1.1.1.3 ! misho 1773: * Function implementing start-point() operation
1.1 misho 1774: * as described in 5.4.3
1775: * ----------------
1776: * location-set start-point(location-set)
1777: *
1778: * For each location x in the argument location-set, start-point adds a
1779: * location of type point to the result location-set. That point represents
1780: * the start point of location x and is determined by the following rules:
1781: *
1782: * - If x is of type point, the start point is x.
1783: * - If x is of type range, the start point is the start point of x.
1784: * - If x is of type root, element, text, comment, or processing instruction,
1785: * - the container node of the start point is x and the index is 0.
1786: * - If x is of type attribute or namespace, the function must signal a
1787: * syntax error.
1788: * ----------------
1789: *
1790: */
1791: static void
1792: xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1793: xmlXPathObjectPtr tmp, obj, point;
1794: xmlLocationSetPtr newset = NULL;
1795: xmlLocationSetPtr oldset = NULL;
1796:
1797: CHECK_ARITY(1);
1798: if ((ctxt->value == NULL) ||
1799: ((ctxt->value->type != XPATH_LOCATIONSET) &&
1800: (ctxt->value->type != XPATH_NODESET)))
1801: XP_ERROR(XPATH_INVALID_TYPE)
1802:
1803: obj = valuePop(ctxt);
1804: if (obj->type == XPATH_NODESET) {
1805: /*
1806: * First convert to a location set
1807: */
1808: tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
1809: xmlXPathFreeObject(obj);
1810: obj = tmp;
1811: }
1812:
1813: newset = xmlXPtrLocationSetCreate(NULL);
1814: if (newset == NULL) {
1815: xmlXPathFreeObject(obj);
1816: XP_ERROR(XPATH_MEMORY_ERROR);
1817: }
1818: oldset = (xmlLocationSetPtr) obj->user;
1819: if (oldset != NULL) {
1820: int i;
1821:
1822: for (i = 0; i < oldset->locNr; i++) {
1823: tmp = oldset->locTab[i];
1824: if (tmp == NULL)
1825: continue;
1826: point = NULL;
1827: switch (tmp->type) {
1828: case XPATH_POINT:
1829: point = xmlXPtrNewPoint(tmp->user, tmp->index);
1830: break;
1831: case XPATH_RANGE: {
1832: xmlNodePtr node = tmp->user;
1833: if (node != NULL) {
1834: if (node->type == XML_ATTRIBUTE_NODE) {
1835: /* TODO: Namespace Nodes ??? */
1836: xmlXPathFreeObject(obj);
1837: xmlXPtrFreeLocationSet(newset);
1838: XP_ERROR(XPTR_SYNTAX_ERROR);
1839: }
1840: point = xmlXPtrNewPoint(node, tmp->index);
1841: }
1842: break;
1843: }
1844: default:
1845: /*** Should we raise an error ?
1846: xmlXPathFreeObject(obj);
1847: xmlXPathFreeObject(newset);
1848: XP_ERROR(XPATH_INVALID_TYPE)
1849: ***/
1850: break;
1851: }
1852: if (point != NULL)
1853: xmlXPtrLocationSetAdd(newset, point);
1854: }
1855: }
1856: xmlXPathFreeObject(obj);
1857: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
1858: }
1859:
1860: /**
1861: * xmlXPtrEndPointFunction:
1862: * @ctxt: the XPointer Parser context
1863: * @nargs: the number of args
1864: *
1.1.1.3 ! misho 1865: * Function implementing end-point() operation
1.1 misho 1866: * as described in 5.4.3
1867: * ----------------------------
1868: * location-set end-point(location-set)
1869: *
1870: * For each location x in the argument location-set, end-point adds a
1871: * location of type point to the result location-set. That point represents
1872: * the end point of location x and is determined by the following rules:
1873: *
1874: * - If x is of type point, the resulting point is x.
1875: * - If x is of type range, the resulting point is the end point of x.
1876: * - If x is of type root or element, the container node of the resulting
1877: * point is x and the index is the number of location children of x.
1878: * - If x is of type text, comment, or processing instruction, the container
1879: * node of the resulting point is x and the index is the length of the
1880: * string-value of x.
1881: * - If x is of type attribute or namespace, the function must signal a
1882: * syntax error.
1883: * ----------------------------
1884: */
1885: static void
1886: xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1887: xmlXPathObjectPtr tmp, obj, point;
1888: xmlLocationSetPtr newset = NULL;
1889: xmlLocationSetPtr oldset = NULL;
1890:
1891: CHECK_ARITY(1);
1892: if ((ctxt->value == NULL) ||
1893: ((ctxt->value->type != XPATH_LOCATIONSET) &&
1894: (ctxt->value->type != XPATH_NODESET)))
1895: XP_ERROR(XPATH_INVALID_TYPE)
1896:
1897: obj = valuePop(ctxt);
1898: if (obj->type == XPATH_NODESET) {
1899: /*
1900: * First convert to a location set
1901: */
1902: tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
1903: xmlXPathFreeObject(obj);
1904: obj = tmp;
1905: }
1906:
1907: newset = xmlXPtrLocationSetCreate(NULL);
1908: oldset = (xmlLocationSetPtr) obj->user;
1909: if (oldset != NULL) {
1910: int i;
1911:
1912: for (i = 0; i < oldset->locNr; i++) {
1913: tmp = oldset->locTab[i];
1914: if (tmp == NULL)
1915: continue;
1916: point = NULL;
1917: switch (tmp->type) {
1918: case XPATH_POINT:
1919: point = xmlXPtrNewPoint(tmp->user, tmp->index);
1920: break;
1921: case XPATH_RANGE: {
1922: xmlNodePtr node = tmp->user2;
1923: if (node != NULL) {
1924: if (node->type == XML_ATTRIBUTE_NODE) {
1925: /* TODO: Namespace Nodes ??? */
1926: xmlXPathFreeObject(obj);
1927: xmlXPtrFreeLocationSet(newset);
1928: XP_ERROR(XPTR_SYNTAX_ERROR);
1929: }
1930: point = xmlXPtrNewPoint(node, tmp->index2);
1931: } else if (tmp->user == NULL) {
1932: point = xmlXPtrNewPoint(node,
1933: xmlXPtrNbLocChildren(node));
1934: }
1935: break;
1936: }
1937: default:
1938: /*** Should we raise an error ?
1939: xmlXPathFreeObject(obj);
1940: xmlXPathFreeObject(newset);
1941: XP_ERROR(XPATH_INVALID_TYPE)
1942: ***/
1943: break;
1944: }
1945: if (point != NULL)
1946: xmlXPtrLocationSetAdd(newset, point);
1947: }
1948: }
1949: xmlXPathFreeObject(obj);
1950: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
1951: }
1952:
1953:
1954: /**
1955: * xmlXPtrCoveringRange:
1956: * @ctxt: the XPointer Parser context
1957: * @loc: the location for which the covering range must be computed
1958: *
1959: * A covering range is a range that wholly encompasses a location
1960: * Section 5.3.3. Covering Ranges for All Location Types
1961: * http://www.w3.org/TR/xptr#N2267
1962: *
1963: * Returns a new location or NULL in case of error
1964: */
1965: static xmlXPathObjectPtr
1966: xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
1967: if (loc == NULL)
1968: return(NULL);
1969: if ((ctxt == NULL) || (ctxt->context == NULL) ||
1970: (ctxt->context->doc == NULL))
1971: return(NULL);
1972: switch (loc->type) {
1973: case XPATH_POINT:
1974: return(xmlXPtrNewRange(loc->user, loc->index,
1975: loc->user, loc->index));
1976: case XPATH_RANGE:
1977: if (loc->user2 != NULL) {
1978: return(xmlXPtrNewRange(loc->user, loc->index,
1979: loc->user2, loc->index2));
1980: } else {
1981: xmlNodePtr node = (xmlNodePtr) loc->user;
1982: if (node == (xmlNodePtr) ctxt->context->doc) {
1983: return(xmlXPtrNewRange(node, 0, node,
1984: xmlXPtrGetArity(node)));
1985: } else {
1986: switch (node->type) {
1987: case XML_ATTRIBUTE_NODE:
1988: /* !!! our model is slightly different than XPath */
1989: return(xmlXPtrNewRange(node, 0, node,
1990: xmlXPtrGetArity(node)));
1991: case XML_ELEMENT_NODE:
1992: case XML_TEXT_NODE:
1993: case XML_CDATA_SECTION_NODE:
1994: case XML_ENTITY_REF_NODE:
1995: case XML_PI_NODE:
1996: case XML_COMMENT_NODE:
1997: case XML_DOCUMENT_NODE:
1998: case XML_NOTATION_NODE:
1999: case XML_HTML_DOCUMENT_NODE: {
2000: int indx = xmlXPtrGetIndex(node);
1.1.1.3 ! misho 2001:
1.1 misho 2002: node = node->parent;
2003: return(xmlXPtrNewRange(node, indx - 1,
2004: node, indx + 1));
2005: }
2006: default:
2007: return(NULL);
2008: }
2009: }
2010: }
2011: default:
2012: TODO /* missed one case ??? */
2013: }
2014: return(NULL);
2015: }
2016:
2017: /**
2018: * xmlXPtrRangeFunction:
2019: * @ctxt: the XPointer Parser context
2020: * @nargs: the number of args
2021: *
2022: * Function implementing the range() function 5.4.3
2023: * location-set range(location-set )
2024: *
2025: * The range function returns ranges covering the locations in
2026: * the argument location-set. For each location x in the argument
2027: * location-set, a range location representing the covering range of
2028: * x is added to the result location-set.
2029: */
2030: static void
2031: xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2032: int i;
2033: xmlXPathObjectPtr set;
2034: xmlLocationSetPtr oldset;
2035: xmlLocationSetPtr newset;
2036:
2037: CHECK_ARITY(1);
2038: if ((ctxt->value == NULL) ||
2039: ((ctxt->value->type != XPATH_LOCATIONSET) &&
2040: (ctxt->value->type != XPATH_NODESET)))
2041: XP_ERROR(XPATH_INVALID_TYPE)
2042:
2043: set = valuePop(ctxt);
2044: if (set->type == XPATH_NODESET) {
2045: xmlXPathObjectPtr tmp;
2046:
2047: /*
2048: * First convert to a location set
2049: */
2050: tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2051: xmlXPathFreeObject(set);
2052: set = tmp;
2053: }
2054: oldset = (xmlLocationSetPtr) set->user;
2055:
2056: /*
2057: * The loop is to compute the covering range for each item and add it
2058: */
2059: newset = xmlXPtrLocationSetCreate(NULL);
2060: for (i = 0;i < oldset->locNr;i++) {
2061: xmlXPtrLocationSetAdd(newset,
2062: xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
2063: }
2064:
2065: /*
2066: * Save the new value and cleanup
2067: */
2068: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2069: xmlXPathFreeObject(set);
2070: }
2071:
2072: /**
2073: * xmlXPtrInsideRange:
2074: * @ctxt: the XPointer Parser context
2075: * @loc: the location for which the inside range must be computed
2076: *
2077: * A inside range is a range described in the range-inside() description
2078: *
2079: * Returns a new location or NULL in case of error
2080: */
2081: static xmlXPathObjectPtr
2082: xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
2083: if (loc == NULL)
2084: return(NULL);
2085: if ((ctxt == NULL) || (ctxt->context == NULL) ||
2086: (ctxt->context->doc == NULL))
2087: return(NULL);
2088: switch (loc->type) {
2089: case XPATH_POINT: {
2090: xmlNodePtr node = (xmlNodePtr) loc->user;
2091: switch (node->type) {
2092: case XML_PI_NODE:
2093: case XML_COMMENT_NODE:
2094: case XML_TEXT_NODE:
2095: case XML_CDATA_SECTION_NODE: {
2096: if (node->content == NULL) {
2097: return(xmlXPtrNewRange(node, 0, node, 0));
2098: } else {
2099: return(xmlXPtrNewRange(node, 0, node,
2100: xmlStrlen(node->content)));
2101: }
2102: }
2103: case XML_ATTRIBUTE_NODE:
2104: case XML_ELEMENT_NODE:
2105: case XML_ENTITY_REF_NODE:
2106: case XML_DOCUMENT_NODE:
2107: case XML_NOTATION_NODE:
2108: case XML_HTML_DOCUMENT_NODE: {
2109: return(xmlXPtrNewRange(node, 0, node,
2110: xmlXPtrGetArity(node)));
2111: }
2112: default:
2113: break;
2114: }
2115: return(NULL);
2116: }
2117: case XPATH_RANGE: {
2118: xmlNodePtr node = (xmlNodePtr) loc->user;
2119: if (loc->user2 != NULL) {
2120: return(xmlXPtrNewRange(node, loc->index,
2121: loc->user2, loc->index2));
2122: } else {
2123: switch (node->type) {
2124: case XML_PI_NODE:
2125: case XML_COMMENT_NODE:
2126: case XML_TEXT_NODE:
2127: case XML_CDATA_SECTION_NODE: {
2128: if (node->content == NULL) {
2129: return(xmlXPtrNewRange(node, 0, node, 0));
2130: } else {
2131: return(xmlXPtrNewRange(node, 0, node,
2132: xmlStrlen(node->content)));
2133: }
2134: }
2135: case XML_ATTRIBUTE_NODE:
2136: case XML_ELEMENT_NODE:
2137: case XML_ENTITY_REF_NODE:
2138: case XML_DOCUMENT_NODE:
2139: case XML_NOTATION_NODE:
2140: case XML_HTML_DOCUMENT_NODE: {
2141: return(xmlXPtrNewRange(node, 0, node,
2142: xmlXPtrGetArity(node)));
2143: }
2144: default:
2145: break;
2146: }
2147: return(NULL);
2148: }
2149: }
2150: default:
2151: TODO /* missed one case ??? */
2152: }
2153: return(NULL);
2154: }
2155:
2156: /**
2157: * xmlXPtrRangeInsideFunction:
2158: * @ctxt: the XPointer Parser context
2159: * @nargs: the number of args
2160: *
2161: * Function implementing the range-inside() function 5.4.3
2162: * location-set range-inside(location-set )
2163: *
2164: * The range-inside function returns ranges covering the contents of
2165: * the locations in the argument location-set. For each location x in
2166: * the argument location-set, a range location is added to the result
2167: * location-set. If x is a range location, then x is added to the
2168: * result location-set. If x is not a range location, then x is used
2169: * as the container location of the start and end points of the range
2170: * location to be added; the index of the start point of the range is
2171: * zero; if the end point is a character point then its index is the
2172: * length of the string-value of x, and otherwise is the number of
2173: * location children of x.
2174: *
2175: */
2176: static void
2177: xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2178: int i;
2179: xmlXPathObjectPtr set;
2180: xmlLocationSetPtr oldset;
2181: xmlLocationSetPtr newset;
2182:
2183: CHECK_ARITY(1);
2184: if ((ctxt->value == NULL) ||
2185: ((ctxt->value->type != XPATH_LOCATIONSET) &&
2186: (ctxt->value->type != XPATH_NODESET)))
2187: XP_ERROR(XPATH_INVALID_TYPE)
2188:
2189: set = valuePop(ctxt);
2190: if (set->type == XPATH_NODESET) {
2191: xmlXPathObjectPtr tmp;
2192:
2193: /*
2194: * First convert to a location set
2195: */
2196: tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2197: xmlXPathFreeObject(set);
2198: set = tmp;
2199: }
2200: oldset = (xmlLocationSetPtr) set->user;
2201:
2202: /*
2203: * The loop is to compute the covering range for each item and add it
2204: */
2205: newset = xmlXPtrLocationSetCreate(NULL);
2206: for (i = 0;i < oldset->locNr;i++) {
2207: xmlXPtrLocationSetAdd(newset,
2208: xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
2209: }
2210:
2211: /*
2212: * Save the new value and cleanup
2213: */
2214: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2215: xmlXPathFreeObject(set);
2216: }
2217:
2218: /**
2219: * xmlXPtrRangeToFunction:
2220: * @ctxt: the XPointer Parser context
2221: * @nargs: the number of args
2222: *
2223: * Implement the range-to() XPointer function
2224: */
2225: void
2226: xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2227: xmlXPathObjectPtr range;
2228: const xmlChar *cur;
2229: xmlXPathObjectPtr res, obj;
2230: xmlXPathObjectPtr tmp;
2231: xmlLocationSetPtr newset = NULL;
2232: xmlNodeSetPtr oldset;
2233: int i;
2234:
2235: if (ctxt == NULL) return;
2236: CHECK_ARITY(1);
2237: /*
2238: * Save the expression pointer since we will have to evaluate
2239: * it multiple times. Initialize the new set.
2240: */
2241: CHECK_TYPE(XPATH_NODESET);
2242: obj = valuePop(ctxt);
2243: oldset = obj->nodesetval;
2244: ctxt->context->node = NULL;
2245:
2246: cur = ctxt->cur;
2247: newset = xmlXPtrLocationSetCreate(NULL);
1.1.1.3 ! misho 2248:
1.1 misho 2249: for (i = 0; i < oldset->nodeNr; i++) {
2250: ctxt->cur = cur;
2251:
2252: /*
2253: * Run the evaluation with a node list made of a single item
2254: * in the nodeset.
2255: */
2256: ctxt->context->node = oldset->nodeTab[i];
2257: tmp = xmlXPathNewNodeSet(ctxt->context->node);
2258: valuePush(ctxt, tmp);
2259:
2260: xmlXPathEvalExpr(ctxt);
2261: CHECK_ERROR;
2262:
2263: /*
2264: * The result of the evaluation need to be tested to
2265: * decided whether the filter succeeded or not
2266: */
2267: res = valuePop(ctxt);
2268: range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
2269: if (range != NULL) {
2270: xmlXPtrLocationSetAdd(newset, range);
2271: }
2272:
2273: /*
2274: * Cleanup
2275: */
2276: if (res != NULL)
2277: xmlXPathFreeObject(res);
2278: if (ctxt->value == tmp) {
2279: res = valuePop(ctxt);
2280: xmlXPathFreeObject(res);
2281: }
1.1.1.3 ! misho 2282:
1.1 misho 2283: ctxt->context->node = NULL;
2284: }
2285:
2286: /*
2287: * The result is used as the new evaluation set.
2288: */
2289: xmlXPathFreeObject(obj);
2290: ctxt->context->node = NULL;
2291: ctxt->context->contextSize = -1;
2292: ctxt->context->proximityPosition = -1;
2293: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2294: }
2295:
2296: /**
2297: * xmlXPtrAdvanceNode:
2298: * @cur: the node
2299: * @level: incremented/decremented to show level in tree
2300: *
2301: * Advance to the next element or text node in document order
1.1.1.3 ! misho 2302: * TODO: add a stack for entering/exiting entities
1.1 misho 2303: *
2304: * Returns -1 in case of failure, 0 otherwise
2305: */
2306: xmlNodePtr
2307: xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
2308: next:
1.1.1.3 ! misho 2309: if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
1.1 misho 2310: return(NULL);
2311: if (cur->children != NULL) {
2312: cur = cur->children ;
2313: if (level != NULL)
2314: (*level)++;
2315: goto found;
2316: }
2317: skip: /* This label should only be needed if something is wrong! */
2318: if (cur->next != NULL) {
2319: cur = cur->next;
2320: goto found;
2321: }
2322: do {
2323: cur = cur->parent;
2324: if (level != NULL)
2325: (*level)--;
2326: if (cur == NULL) return(NULL);
2327: if (cur->next != NULL) {
2328: cur = cur->next;
2329: goto found;
2330: }
2331: } while (cur != NULL);
2332:
2333: found:
2334: if ((cur->type != XML_ELEMENT_NODE) &&
2335: (cur->type != XML_TEXT_NODE) &&
2336: (cur->type != XML_DOCUMENT_NODE) &&
2337: (cur->type != XML_HTML_DOCUMENT_NODE) &&
2338: (cur->type != XML_CDATA_SECTION_NODE)) {
2339: if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */
2340: TODO
2341: goto skip;
2342: }
2343: goto next;
2344: }
2345: return(cur);
2346: }
2347:
2348: /**
2349: * xmlXPtrAdvanceChar:
2350: * @node: the node
2351: * @indx: the indx
2352: * @bytes: the number of bytes
2353: *
2354: * Advance a point of the associated number of bytes (not UTF8 chars)
2355: *
2356: * Returns -1 in case of failure, 0 otherwise
2357: */
2358: static int
2359: xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) {
2360: xmlNodePtr cur;
2361: int pos;
2362: int len;
2363:
2364: if ((node == NULL) || (indx == NULL))
2365: return(-1);
2366: cur = *node;
1.1.1.3 ! misho 2367: if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
1.1 misho 2368: return(-1);
2369: pos = *indx;
2370:
2371: while (bytes >= 0) {
2372: /*
2373: * First position to the beginning of the first text node
2374: * corresponding to this point
2375: */
2376: while ((cur != NULL) &&
2377: ((cur->type == XML_ELEMENT_NODE) ||
2378: (cur->type == XML_DOCUMENT_NODE) ||
2379: (cur->type == XML_HTML_DOCUMENT_NODE))) {
2380: if (pos > 0) {
2381: cur = xmlXPtrGetNthChild(cur, pos);
2382: pos = 0;
2383: } else {
2384: cur = xmlXPtrAdvanceNode(cur, NULL);
2385: pos = 0;
2386: }
2387: }
2388:
2389: if (cur == NULL) {
2390: *node = NULL;
2391: *indx = 0;
2392: return(-1);
2393: }
2394:
2395: /*
2396: * if there is no move needed return the current value.
2397: */
2398: if (pos == 0) pos = 1;
2399: if (bytes == 0) {
2400: *node = cur;
2401: *indx = pos;
2402: return(0);
2403: }
2404: /*
1.1.1.3 ! misho 2405: * We should have a text (or cdata) node ...
1.1 misho 2406: */
2407: len = 0;
2408: if ((cur->type != XML_ELEMENT_NODE) &&
2409: (cur->content != NULL)) {
2410: len = xmlStrlen(cur->content);
2411: }
2412: if (pos > len) {
2413: /* Strange, the indx in the text node is greater than it's len */
2414: STRANGE
2415: pos = len;
2416: }
2417: if (pos + bytes >= len) {
2418: bytes -= (len - pos);
2419: cur = xmlXPtrAdvanceNode(cur, NULL);
2420: pos = 0;
2421: } else if (pos + bytes < len) {
2422: pos += bytes;
2423: *node = cur;
2424: *indx = pos;
2425: return(0);
2426: }
2427: }
2428: return(-1);
2429: }
2430:
2431: /**
2432: * xmlXPtrMatchString:
2433: * @string: the string to search
2434: * @start: the start textnode
2435: * @startindex: the start index
2436: * @end: the end textnode IN/OUT
2437: * @endindex: the end index IN/OUT
2438: *
2439: * Check whether the document contains @string at the position
2440: * (@start, @startindex) and limited by the (@end, @endindex) point
2441: *
2442: * Returns -1 in case of failure, 0 if not found, 1 if found in which case
2443: * (@start, @startindex) will indicate the position of the beginning
2444: * of the range and (@end, @endindex) will indicate the end
2445: * of the range
2446: */
2447: static int
2448: xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
2449: xmlNodePtr *end, int *endindex) {
2450: xmlNodePtr cur;
2451: int pos; /* 0 based */
2452: int len; /* in bytes */
2453: int stringlen; /* in bytes */
2454: int match;
2455:
2456: if (string == NULL)
2457: return(-1);
1.1.1.3 ! misho 2458: if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
1.1 misho 2459: return(-1);
1.1.1.3 ! misho 2460: if ((end == NULL) || (*end == NULL) ||
! 2461: ((*end)->type == XML_NAMESPACE_DECL) || (endindex == NULL))
1.1 misho 2462: return(-1);
2463: cur = start;
2464: if (cur == NULL)
2465: return(-1);
2466: pos = startindex - 1;
2467: stringlen = xmlStrlen(string);
2468:
2469: while (stringlen > 0) {
2470: if ((cur == *end) && (pos + stringlen > *endindex))
2471: return(0);
2472:
2473: if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
2474: len = xmlStrlen(cur->content);
2475: if (len >= pos + stringlen) {
2476: match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
2477: if (match) {
2478: #ifdef DEBUG_RANGES
2479: xmlGenericError(xmlGenericErrorContext,
2480: "found range %d bytes at index %d of ->",
2481: stringlen, pos + 1);
2482: xmlDebugDumpString(stdout, cur->content);
2483: xmlGenericError(xmlGenericErrorContext, "\n");
2484: #endif
2485: *end = cur;
2486: *endindex = pos + stringlen;
2487: return(1);
2488: } else {
2489: return(0);
2490: }
2491: } else {
2492: int sub = len - pos;
2493: match = (!xmlStrncmp(&cur->content[pos], string, sub));
2494: if (match) {
2495: #ifdef DEBUG_RANGES
2496: xmlGenericError(xmlGenericErrorContext,
2497: "found subrange %d bytes at index %d of ->",
2498: sub, pos + 1);
2499: xmlDebugDumpString(stdout, cur->content);
2500: xmlGenericError(xmlGenericErrorContext, "\n");
2501: #endif
2502: string = &string[sub];
2503: stringlen -= sub;
2504: } else {
2505: return(0);
2506: }
2507: }
2508: }
2509: cur = xmlXPtrAdvanceNode(cur, NULL);
2510: if (cur == NULL)
2511: return(0);
2512: pos = 0;
2513: }
2514: return(1);
2515: }
2516:
2517: /**
2518: * xmlXPtrSearchString:
2519: * @string: the string to search
2520: * @start: the start textnode IN/OUT
2521: * @startindex: the start index IN/OUT
2522: * @end: the end textnode
2523: * @endindex: the end index
2524: *
2525: * Search the next occurrence of @string within the document content
2526: * until the (@end, @endindex) point is reached
2527: *
2528: * Returns -1 in case of failure, 0 if not found, 1 if found in which case
2529: * (@start, @startindex) will indicate the position of the beginning
2530: * of the range and (@end, @endindex) will indicate the end
2531: * of the range
2532: */
2533: static int
2534: xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
2535: xmlNodePtr *end, int *endindex) {
2536: xmlNodePtr cur;
2537: const xmlChar *str;
2538: int pos; /* 0 based */
2539: int len; /* in bytes */
2540: xmlChar first;
2541:
2542: if (string == NULL)
2543: return(-1);
1.1.1.3 ! misho 2544: if ((start == NULL) || (*start == NULL) ||
! 2545: ((*start)->type == XML_NAMESPACE_DECL) || (startindex == NULL))
1.1 misho 2546: return(-1);
2547: if ((end == NULL) || (endindex == NULL))
2548: return(-1);
2549: cur = *start;
2550: pos = *startindex - 1;
2551: first = string[0];
2552:
2553: while (cur != NULL) {
2554: if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
2555: len = xmlStrlen(cur->content);
2556: while (pos <= len) {
2557: if (first != 0) {
2558: str = xmlStrchr(&cur->content[pos], first);
2559: if (str != NULL) {
2560: pos = (str - (xmlChar *)(cur->content));
2561: #ifdef DEBUG_RANGES
2562: xmlGenericError(xmlGenericErrorContext,
2563: "found '%c' at index %d of ->",
2564: first, pos + 1);
2565: xmlDebugDumpString(stdout, cur->content);
2566: xmlGenericError(xmlGenericErrorContext, "\n");
2567: #endif
2568: if (xmlXPtrMatchString(string, cur, pos + 1,
2569: end, endindex)) {
2570: *start = cur;
2571: *startindex = pos + 1;
2572: return(1);
2573: }
2574: pos++;
2575: } else {
2576: pos = len + 1;
2577: }
2578: } else {
2579: /*
2580: * An empty string is considered to match before each
2581: * character of the string-value and after the final
1.1.1.3 ! misho 2582: * character.
1.1 misho 2583: */
2584: #ifdef DEBUG_RANGES
2585: xmlGenericError(xmlGenericErrorContext,
2586: "found '' at index %d of ->",
2587: pos + 1);
2588: xmlDebugDumpString(stdout, cur->content);
2589: xmlGenericError(xmlGenericErrorContext, "\n");
2590: #endif
2591: *start = cur;
2592: *startindex = pos + 1;
2593: *end = cur;
2594: *endindex = pos + 1;
2595: return(1);
2596: }
2597: }
2598: }
2599: if ((cur == *end) && (pos >= *endindex))
2600: return(0);
2601: cur = xmlXPtrAdvanceNode(cur, NULL);
2602: if (cur == NULL)
2603: return(0);
2604: pos = 1;
2605: }
2606: return(0);
2607: }
2608:
2609: /**
2610: * xmlXPtrGetLastChar:
2611: * @node: the node
2612: * @index: the index
2613: *
2614: * Computes the point coordinates of the last char of this point
2615: *
2616: * Returns -1 in case of failure, 0 otherwise
2617: */
2618: static int
2619: xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) {
2620: xmlNodePtr cur;
2621: int pos, len = 0;
2622:
1.1.1.3 ! misho 2623: if ((node == NULL) || (*node == NULL) ||
! 2624: ((*node)->type == XML_NAMESPACE_DECL) || (indx == NULL))
1.1 misho 2625: return(-1);
2626: cur = *node;
2627: pos = *indx;
2628:
2629: if ((cur->type == XML_ELEMENT_NODE) ||
2630: (cur->type == XML_DOCUMENT_NODE) ||
2631: (cur->type == XML_HTML_DOCUMENT_NODE)) {
2632: if (pos > 0) {
2633: cur = xmlXPtrGetNthChild(cur, pos);
2634: }
2635: }
2636: while (cur != NULL) {
2637: if (cur->last != NULL)
2638: cur = cur->last;
2639: else if ((cur->type != XML_ELEMENT_NODE) &&
2640: (cur->content != NULL)) {
2641: len = xmlStrlen(cur->content);
2642: break;
2643: } else {
2644: return(-1);
2645: }
2646: }
2647: if (cur == NULL)
2648: return(-1);
2649: *node = cur;
2650: *indx = len;
2651: return(0);
2652: }
2653:
2654: /**
2655: * xmlXPtrGetStartPoint:
2656: * @obj: an range
2657: * @node: the resulting node
2658: * @indx: the resulting index
2659: *
2660: * read the object and return the start point coordinates.
2661: *
2662: * Returns -1 in case of failure, 0 otherwise
2663: */
2664: static int
2665: xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
2666: if ((obj == NULL) || (node == NULL) || (indx == NULL))
2667: return(-1);
2668:
2669: switch (obj->type) {
2670: case XPATH_POINT:
2671: *node = obj->user;
2672: if (obj->index <= 0)
2673: *indx = 0;
2674: else
2675: *indx = obj->index;
2676: return(0);
2677: case XPATH_RANGE:
2678: *node = obj->user;
2679: if (obj->index <= 0)
2680: *indx = 0;
2681: else
2682: *indx = obj->index;
2683: return(0);
2684: default:
2685: break;
2686: }
2687: return(-1);
2688: }
2689:
2690: /**
2691: * xmlXPtrGetEndPoint:
2692: * @obj: an range
2693: * @node: the resulting node
2694: * @indx: the resulting indx
2695: *
2696: * read the object and return the end point coordinates.
2697: *
2698: * Returns -1 in case of failure, 0 otherwise
2699: */
2700: static int
2701: xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
2702: if ((obj == NULL) || (node == NULL) || (indx == NULL))
2703: return(-1);
2704:
2705: switch (obj->type) {
2706: case XPATH_POINT:
2707: *node = obj->user;
2708: if (obj->index <= 0)
2709: *indx = 0;
2710: else
2711: *indx = obj->index;
2712: return(0);
2713: case XPATH_RANGE:
2714: *node = obj->user;
2715: if (obj->index <= 0)
2716: *indx = 0;
2717: else
2718: *indx = obj->index;
2719: return(0);
2720: default:
2721: break;
2722: }
2723: return(-1);
2724: }
2725:
2726: /**
2727: * xmlXPtrStringRangeFunction:
2728: * @ctxt: the XPointer Parser context
2729: * @nargs: the number of args
2730: *
2731: * Function implementing the string-range() function
1.1.1.3 ! misho 2732: * range as described in 5.4.2
1.1 misho 2733: *
2734: * ------------------------------
2735: * [Definition: For each location in the location-set argument,
2736: * string-range returns a set of string ranges, a set of substrings in a
2737: * string. Specifically, the string-value of the location is searched for
2738: * substrings that match the string argument, and the resulting location-set
2739: * will contain a range location for each non-overlapping match.]
2740: * An empty string is considered to match before each character of the
2741: * string-value and after the final character. Whitespace in a string
2742: * is matched literally, with no normalization except that provided by
2743: * XML for line ends. The third argument gives the position of the first
2744: * character to be in the resulting range, relative to the start of the
2745: * match. The default value is 1, which makes the range start immediately
2746: * before the first character of the matched string. The fourth argument
2747: * gives the number of characters in the range; the default is that the
2748: * range extends to the end of the matched string.
2749: *
2750: * Element boundaries, as well as entire embedded nodes such as processing
2751: * instructions and comments, are ignored as defined in [XPath].
2752: *
2753: * If the string in the second argument is not found in the string-value
2754: * of the location, or if a value in the third or fourth argument indicates
2755: * a string that is beyond the beginning or end of the document, the
2756: * expression fails.
2757: *
2758: * The points of the range-locations in the returned location-set will
2759: * all be character points.
2760: * ------------------------------
2761: */
2762: static void
2763: xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2764: int i, startindex, endindex = 0, fendindex;
2765: xmlNodePtr start, end = 0, fend;
2766: xmlXPathObjectPtr set;
2767: xmlLocationSetPtr oldset;
2768: xmlLocationSetPtr newset;
2769: xmlXPathObjectPtr string;
2770: xmlXPathObjectPtr position = NULL;
2771: xmlXPathObjectPtr number = NULL;
2772: int found, pos = 0, num = 0;
2773:
2774: /*
2775: * Grab the arguments
2776: */
2777: if ((nargs < 2) || (nargs > 4))
2778: XP_ERROR(XPATH_INVALID_ARITY);
2779:
2780: if (nargs >= 4) {
2781: CHECK_TYPE(XPATH_NUMBER);
2782: number = valuePop(ctxt);
2783: if (number != NULL)
2784: num = (int) number->floatval;
2785: }
2786: if (nargs >= 3) {
2787: CHECK_TYPE(XPATH_NUMBER);
2788: position = valuePop(ctxt);
2789: if (position != NULL)
2790: pos = (int) position->floatval;
2791: }
2792: CHECK_TYPE(XPATH_STRING);
2793: string = valuePop(ctxt);
2794: if ((ctxt->value == NULL) ||
2795: ((ctxt->value->type != XPATH_LOCATIONSET) &&
2796: (ctxt->value->type != XPATH_NODESET)))
2797: XP_ERROR(XPATH_INVALID_TYPE)
2798:
2799: set = valuePop(ctxt);
2800: newset = xmlXPtrLocationSetCreate(NULL);
2801: if (set->nodesetval == NULL) {
2802: goto error;
2803: }
2804: if (set->type == XPATH_NODESET) {
2805: xmlXPathObjectPtr tmp;
2806:
2807: /*
2808: * First convert to a location set
2809: */
2810: tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2811: xmlXPathFreeObject(set);
2812: set = tmp;
2813: }
2814: oldset = (xmlLocationSetPtr) set->user;
2815:
2816: /*
2817: * The loop is to search for each element in the location set
2818: * the list of location set corresponding to that search
2819: */
2820: for (i = 0;i < oldset->locNr;i++) {
2821: #ifdef DEBUG_RANGES
2822: xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0);
2823: #endif
2824:
2825: xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
2826: xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
2827: xmlXPtrAdvanceChar(&start, &startindex, 0);
2828: xmlXPtrGetLastChar(&end, &endindex);
2829:
2830: #ifdef DEBUG_RANGES
2831: xmlGenericError(xmlGenericErrorContext,
2832: "from index %d of ->", startindex);
2833: xmlDebugDumpString(stdout, start->content);
2834: xmlGenericError(xmlGenericErrorContext, "\n");
2835: xmlGenericError(xmlGenericErrorContext,
2836: "to index %d of ->", endindex);
2837: xmlDebugDumpString(stdout, end->content);
2838: xmlGenericError(xmlGenericErrorContext, "\n");
2839: #endif
2840: do {
2841: fend = end;
2842: fendindex = endindex;
2843: found = xmlXPtrSearchString(string->stringval, &start, &startindex,
2844: &fend, &fendindex);
2845: if (found == 1) {
2846: if (position == NULL) {
2847: xmlXPtrLocationSetAdd(newset,
2848: xmlXPtrNewRange(start, startindex, fend, fendindex));
2849: } else if (xmlXPtrAdvanceChar(&start, &startindex,
2850: pos - 1) == 0) {
2851: if ((number != NULL) && (num > 0)) {
2852: int rindx;
2853: xmlNodePtr rend;
2854: rend = start;
2855: rindx = startindex - 1;
2856: if (xmlXPtrAdvanceChar(&rend, &rindx,
2857: num) == 0) {
2858: xmlXPtrLocationSetAdd(newset,
2859: xmlXPtrNewRange(start, startindex,
2860: rend, rindx));
2861: }
2862: } else if ((number != NULL) && (num <= 0)) {
2863: xmlXPtrLocationSetAdd(newset,
2864: xmlXPtrNewRange(start, startindex,
2865: start, startindex));
2866: } else {
2867: xmlXPtrLocationSetAdd(newset,
2868: xmlXPtrNewRange(start, startindex,
2869: fend, fendindex));
2870: }
2871: }
2872: start = fend;
2873: startindex = fendindex;
2874: if (string->stringval[0] == 0)
2875: startindex++;
2876: }
2877: } while (found == 1);
2878: }
2879:
2880: /*
2881: * Save the new value and cleanup
2882: */
2883: error:
2884: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2885: xmlXPathFreeObject(set);
2886: xmlXPathFreeObject(string);
2887: if (position) xmlXPathFreeObject(position);
2888: if (number) xmlXPathFreeObject(number);
2889: }
2890:
2891: /**
2892: * xmlXPtrEvalRangePredicate:
2893: * @ctxt: the XPointer Parser context
2894: *
2895: * [8] Predicate ::= '[' PredicateExpr ']'
1.1.1.3 ! misho 2896: * [9] PredicateExpr ::= Expr
1.1 misho 2897: *
2898: * Evaluate a predicate as in xmlXPathEvalPredicate() but for
2899: * a Location Set instead of a node set
2900: */
2901: void
2902: xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) {
2903: const xmlChar *cur;
2904: xmlXPathObjectPtr res;
2905: xmlXPathObjectPtr obj, tmp;
2906: xmlLocationSetPtr newset = NULL;
2907: xmlLocationSetPtr oldset;
2908: int i;
2909:
2910: if (ctxt == NULL) return;
2911:
2912: SKIP_BLANKS;
2913: if (CUR != '[') {
2914: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
2915: }
2916: NEXT;
2917: SKIP_BLANKS;
2918:
2919: /*
2920: * Extract the old set, and then evaluate the result of the
2921: * expression for all the element in the set. use it to grow
2922: * up a new set.
2923: */
2924: CHECK_TYPE(XPATH_LOCATIONSET);
2925: obj = valuePop(ctxt);
2926: oldset = obj->user;
2927: ctxt->context->node = NULL;
2928:
2929: if ((oldset == NULL) || (oldset->locNr == 0)) {
2930: ctxt->context->contextSize = 0;
2931: ctxt->context->proximityPosition = 0;
2932: xmlXPathEvalExpr(ctxt);
2933: res = valuePop(ctxt);
2934: if (res != NULL)
2935: xmlXPathFreeObject(res);
2936: valuePush(ctxt, obj);
2937: CHECK_ERROR;
2938: } else {
2939: /*
2940: * Save the expression pointer since we will have to evaluate
2941: * it multiple times. Initialize the new set.
2942: */
2943: cur = ctxt->cur;
2944: newset = xmlXPtrLocationSetCreate(NULL);
1.1.1.3 ! misho 2945:
1.1 misho 2946: for (i = 0; i < oldset->locNr; i++) {
2947: ctxt->cur = cur;
2948:
2949: /*
2950: * Run the evaluation with a node list made of a single item
2951: * in the nodeset.
2952: */
2953: ctxt->context->node = oldset->locTab[i]->user;
2954: tmp = xmlXPathNewNodeSet(ctxt->context->node);
2955: valuePush(ctxt, tmp);
2956: ctxt->context->contextSize = oldset->locNr;
2957: ctxt->context->proximityPosition = i + 1;
2958:
2959: xmlXPathEvalExpr(ctxt);
2960: CHECK_ERROR;
2961:
2962: /*
2963: * The result of the evaluation need to be tested to
2964: * decided whether the filter succeeded or not
2965: */
2966: res = valuePop(ctxt);
2967: if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
2968: xmlXPtrLocationSetAdd(newset,
2969: xmlXPathObjectCopy(oldset->locTab[i]));
2970: }
2971:
2972: /*
2973: * Cleanup
2974: */
2975: if (res != NULL)
2976: xmlXPathFreeObject(res);
2977: if (ctxt->value == tmp) {
2978: res = valuePop(ctxt);
2979: xmlXPathFreeObject(res);
2980: }
1.1.1.3 ! misho 2981:
1.1 misho 2982: ctxt->context->node = NULL;
2983: }
2984:
2985: /*
2986: * The result is used as the new evaluation set.
2987: */
2988: xmlXPathFreeObject(obj);
2989: ctxt->context->node = NULL;
2990: ctxt->context->contextSize = -1;
2991: ctxt->context->proximityPosition = -1;
2992: valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2993: }
2994: if (CUR != ']') {
2995: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
2996: }
2997:
2998: NEXT;
2999: SKIP_BLANKS;
3000: }
3001:
3002: #define bottom_xpointer
3003: #include "elfgcchack.h"
3004: #endif
3005:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>