/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tktextmark.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tktextmark.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (hide annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (7 years, 4 months ago) by dashley
File MIME type: text/plain
File size: 23339 byte(s)
License and property (keyword) changes.
1 dashley 69 /* $Header$ */
2 dashley 25
3     /*
4     * tkTextMark.c --
5     *
6     * This file contains the procedure that implement marks for
7     * text widgets.
8     *
9     * Copyright (c) 1994 The Regents of the University of California.
10     * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11     *
12     * See the file "license.terms" for information on usage and redistribution
13     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14     *
15     * RCS: @(#) $Id: tktextmark.c,v 1.1.1.1 2001/06/13 05:10:40 dtashley Exp $
16     */
17    
18     #include "tkInt.h"
19     #include "tkText.h"
20     #include "tkPort.h"
21    
22     /*
23     * Macro that determines the size of a mark segment:
24     */
25    
26     #define MSEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
27     + sizeof(TkTextMark)))
28    
29     /*
30     * Forward references for procedures defined in this file:
31     */
32    
33     static void InsertUndisplayProc _ANSI_ARGS_((TkText *textPtr,
34     TkTextDispChunk *chunkPtr));
35     static int MarkDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
36     TkTextLine *linePtr, int treeGone));
37     static TkTextSegment * MarkCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
38     TkTextLine *linePtr));
39     static void MarkCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
40     TkTextLine *linePtr));
41     static int MarkLayoutProc _ANSI_ARGS_((TkText *textPtr,
42     TkTextIndex *indexPtr, TkTextSegment *segPtr,
43     int offset, int maxX, int maxChars,
44     int noCharsYet, TkWrapMode wrapMode,
45     TkTextDispChunk *chunkPtr));
46     static int MarkFindNext _ANSI_ARGS_((Tcl_Interp *interp,
47     TkText *textPtr, char *markName));
48     static int MarkFindPrev _ANSI_ARGS_((Tcl_Interp *interp,
49     TkText *textPtr, char *markName));
50    
51    
52     /*
53     * The following structures declare the "mark" segment types.
54     * There are actually two types for marks, one with left gravity
55     * and one with right gravity. They are identical except for
56     * their gravity property.
57     */
58    
59     Tk_SegType tkTextRightMarkType = {
60     "mark", /* name */
61     0, /* leftGravity */
62     (Tk_SegSplitProc *) NULL, /* splitProc */
63     MarkDeleteProc, /* deleteProc */
64     MarkCleanupProc, /* cleanupProc */
65     (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */
66     MarkLayoutProc, /* layoutProc */
67     MarkCheckProc /* checkProc */
68     };
69    
70     Tk_SegType tkTextLeftMarkType = {
71     "mark", /* name */
72     1, /* leftGravity */
73     (Tk_SegSplitProc *) NULL, /* splitProc */
74     MarkDeleteProc, /* deleteProc */
75     MarkCleanupProc, /* cleanupProc */
76     (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */
77     MarkLayoutProc, /* layoutProc */
78     MarkCheckProc /* checkProc */
79     };
80    
81     /*
82     *--------------------------------------------------------------
83     *
84     * TkTextMarkCmd --
85     *
86     * This procedure is invoked to process the "mark" options of
87     * the widget command for text widgets. See the user documentation
88     * for details on what it does.
89     *
90     * Results:
91     * A standard Tcl result.
92     *
93     * Side effects:
94     * See the user documentation.
95     *
96     *--------------------------------------------------------------
97     */
98    
99     int
100     TkTextMarkCmd(textPtr, interp, argc, argv)
101     register TkText *textPtr; /* Information about text widget. */
102     Tcl_Interp *interp; /* Current interpreter. */
103     int argc; /* Number of arguments. */
104     char **argv; /* Argument strings. Someone else has already
105     * parsed this command enough to know that
106     * argv[1] is "mark". */
107     {
108     int c, i;
109     size_t length;
110     Tcl_HashEntry *hPtr;
111     TkTextSegment *markPtr;
112     Tcl_HashSearch search;
113     TkTextIndex index;
114     Tk_SegType *newTypePtr;
115    
116     if (argc < 3) {
117     Tcl_AppendResult(interp, "wrong # args: should be \"",
118     argv[0], " mark option ?arg arg ...?\"", (char *) NULL);
119     return TCL_ERROR;
120     }
121     c = argv[2][0];
122     length = strlen(argv[2]);
123     if ((c == 'g') && (strncmp(argv[2], "gravity", length) == 0)) {
124     if (argc < 4 || argc > 5) {
125     Tcl_AppendResult(interp, "wrong # args: should be \"",
126     argv[0], " mark gravity markName ?gravity?\"",
127     (char *) NULL);
128     return TCL_ERROR;
129     }
130     hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[3]);
131     if (hPtr == NULL) {
132     Tcl_AppendResult(interp, "there is no mark named \"",
133     argv[3], "\"", (char *) NULL);
134     return TCL_ERROR;
135     }
136     markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
137     if (argc == 4) {
138     if (markPtr->typePtr == &tkTextRightMarkType) {
139     Tcl_SetResult(interp, "right", TCL_STATIC);
140     } else {
141     Tcl_SetResult(interp, "left", TCL_STATIC);
142     }
143     return TCL_OK;
144     }
145     length = strlen(argv[4]);
146     c = argv[4][0];
147     if ((c == 'l') && (strncmp(argv[4], "left", length) == 0)) {
148     newTypePtr = &tkTextLeftMarkType;
149     } else if ((c == 'r') && (strncmp(argv[4], "right", length) == 0)) {
150     newTypePtr = &tkTextRightMarkType;
151     } else {
152     Tcl_AppendResult(interp, "bad mark gravity \"",
153     argv[4], "\": must be left or right", (char *) NULL);
154     return TCL_ERROR;
155     }
156     TkTextMarkSegToIndex(textPtr, markPtr, &index);
157     TkBTreeUnlinkSegment(textPtr->tree, markPtr,
158     markPtr->body.mark.linePtr);
159     markPtr->typePtr = newTypePtr;
160     TkBTreeLinkSegment(markPtr, &index);
161     } else if ((c == 'n') && (strncmp(argv[2], "names", length) == 0)) {
162     if (argc != 3) {
163     Tcl_AppendResult(interp, "wrong # args: should be \"",
164     argv[0], " mark names\"", (char *) NULL);
165     return TCL_ERROR;
166     }
167     for (hPtr = Tcl_FirstHashEntry(&textPtr->markTable, &search);
168     hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
169     Tcl_AppendElement(interp,
170     Tcl_GetHashKey(&textPtr->markTable, hPtr));
171     }
172     } else if ((c == 'n') && (strncmp(argv[2], "next", length) == 0)) {
173     if (argc != 4) {
174     Tcl_AppendResult(interp, "wrong # args: should be \"",
175     argv[0], " mark next index\"", (char *) NULL);
176     return TCL_ERROR;
177     }
178     return MarkFindNext(interp, textPtr, argv[3]);
179     } else if ((c == 'p') && (strncmp(argv[2], "previous", length) == 0)) {
180     if (argc != 4) {
181     Tcl_AppendResult(interp, "wrong # args: should be \"",
182     argv[0], " mark previous index\"", (char *) NULL);
183     return TCL_ERROR;
184     }
185     return MarkFindPrev(interp, textPtr, argv[3]);
186     } else if ((c == 's') && (strncmp(argv[2], "set", length) == 0)) {
187     if (argc != 5) {
188     Tcl_AppendResult(interp, "wrong # args: should be \"",
189     argv[0], " mark set markName index\"", (char *) NULL);
190     return TCL_ERROR;
191     }
192     if (TkTextGetIndex(interp, textPtr, argv[4], &index) != TCL_OK) {
193     return TCL_ERROR;
194     }
195     TkTextSetMark(textPtr, argv[3], &index);
196     } else if ((c == 'u') && (strncmp(argv[2], "unset", length) == 0)) {
197     for (i = 3; i < argc; i++) {
198     hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[i]);
199     if (hPtr != NULL) {
200     markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
201     if ((markPtr == textPtr->insertMarkPtr)
202     || (markPtr == textPtr->currentMarkPtr)) {
203     continue;
204     }
205     TkBTreeUnlinkSegment(textPtr->tree, markPtr,
206     markPtr->body.mark.linePtr);
207     Tcl_DeleteHashEntry(hPtr);
208     ckfree((char *) markPtr);
209     }
210     }
211     } else {
212     Tcl_AppendResult(interp, "bad mark option \"", argv[2],
213     "\": must be gravity, names, next, previous, set, or unset",
214     (char *) NULL);
215     return TCL_ERROR;
216     }
217     return TCL_OK;
218     }
219    
220     /*
221     *----------------------------------------------------------------------
222     *
223     * TkTextSetMark --
224     *
225     * Set a mark to a particular position, creating a new mark if
226     * one doesn't already exist.
227     *
228     * Results:
229     * The return value is a pointer to the mark that was just set.
230     *
231     * Side effects:
232     * A new mark is created, or an existing mark is moved.
233     *
234     *----------------------------------------------------------------------
235     */
236    
237     TkTextSegment *
238     TkTextSetMark(textPtr, name, indexPtr)
239     TkText *textPtr; /* Text widget in which to create mark. */
240     char *name; /* Name of mark to set. */
241     TkTextIndex *indexPtr; /* Where to set mark. */
242     {
243     Tcl_HashEntry *hPtr;
244     TkTextSegment *markPtr;
245     TkTextIndex insertIndex;
246     int new;
247    
248     hPtr = Tcl_CreateHashEntry(&textPtr->markTable, name, &new);
249     markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
250     if (!new) {
251     /*
252     * If this is the insertion point that's being moved, be sure
253     * to force a display update at the old position. Also, don't
254     * let the insertion cursor be after the final newline of the
255     * file.
256     */
257    
258     if (markPtr == textPtr->insertMarkPtr) {
259     TkTextIndex index, index2;
260     TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index);
261     TkTextIndexForwChars(&index, 1, &index2);
262     TkTextChanged(textPtr, &index, &index2);
263     if (TkBTreeLineIndex(indexPtr->linePtr)
264     == TkBTreeNumLines(textPtr->tree)) {
265     TkTextIndexBackChars(indexPtr, 1, &insertIndex);
266     indexPtr = &insertIndex;
267     }
268     }
269     TkBTreeUnlinkSegment(textPtr->tree, markPtr,
270     markPtr->body.mark.linePtr);
271     } else {
272     markPtr = (TkTextSegment *) ckalloc(MSEG_SIZE);
273     markPtr->typePtr = &tkTextRightMarkType;
274     markPtr->size = 0;
275     markPtr->body.mark.textPtr = textPtr;
276     markPtr->body.mark.linePtr = indexPtr->linePtr;
277     markPtr->body.mark.hPtr = hPtr;
278     Tcl_SetHashValue(hPtr, markPtr);
279     }
280     TkBTreeLinkSegment(markPtr, indexPtr);
281    
282     /*
283     * If the mark is the insertion cursor, then update the screen at the
284     * mark's new location.
285     */
286    
287     if (markPtr == textPtr->insertMarkPtr) {
288     TkTextIndex index2;
289    
290     TkTextIndexForwChars(indexPtr, 1, &index2);
291     TkTextChanged(textPtr, indexPtr, &index2);
292     }
293     return markPtr;
294     }
295    
296     /*
297     *--------------------------------------------------------------
298     *
299     * TkTextMarkSegToIndex --
300     *
301     * Given a segment that is a mark, create an index that
302     * refers to the next text character (or other text segment
303     * with non-zero size) after the mark.
304     *
305     * Results:
306     * *IndexPtr is filled in with index information.
307     *
308     * Side effects:
309     * None.
310     *
311     *--------------------------------------------------------------
312     */
313    
314     void
315     TkTextMarkSegToIndex(textPtr, markPtr, indexPtr)
316     TkText *textPtr; /* Text widget containing mark. */
317     TkTextSegment *markPtr; /* Mark segment. */
318     TkTextIndex *indexPtr; /* Index information gets stored here. */
319     {
320     TkTextSegment *segPtr;
321    
322     indexPtr->tree = textPtr->tree;
323     indexPtr->linePtr = markPtr->body.mark.linePtr;
324     indexPtr->byteIndex = 0;
325     for (segPtr = indexPtr->linePtr->segPtr; segPtr != markPtr;
326     segPtr = segPtr->nextPtr) {
327     indexPtr->byteIndex += segPtr->size;
328     }
329     }
330    
331     /*
332     *--------------------------------------------------------------
333     *
334     * TkTextMarkNameToIndex --
335     *
336     * Given the name of a mark, return an index corresponding
337     * to the mark name.
338     *
339     * Results:
340     * The return value is TCL_OK if "name" exists as a mark in
341     * the text widget. In this case *indexPtr is filled in with
342     * the next segment whose after the mark whose size is
343     * non-zero. TCL_ERROR is returned if the mark doesn't exist
344     * in the text widget.
345     *
346     * Side effects:
347     * None.
348     *
349     *--------------------------------------------------------------
350     */
351    
352     int
353     TkTextMarkNameToIndex(textPtr, name, indexPtr)
354     TkText *textPtr; /* Text widget containing mark. */
355     char *name; /* Name of mark. */
356     TkTextIndex *indexPtr; /* Index information gets stored here. */
357     {
358     Tcl_HashEntry *hPtr;
359    
360     hPtr = Tcl_FindHashEntry(&textPtr->markTable, name);
361     if (hPtr == NULL) {
362     return TCL_ERROR;
363     }
364     TkTextMarkSegToIndex(textPtr, (TkTextSegment *) Tcl_GetHashValue(hPtr),
365     indexPtr);
366     return TCL_OK;
367     }
368    
369     /*
370     *--------------------------------------------------------------
371     *
372     * MarkDeleteProc --
373     *
374     * This procedure is invoked by the text B-tree code whenever
375     * a mark lies in a range of characters being deleted.
376     *
377     * Results:
378     * Returns 1 to indicate that deletion has been rejected.
379     *
380     * Side effects:
381     * None (even if the whole tree is being deleted we don't
382     * free up the mark; it will be done elsewhere).
383     *
384     *--------------------------------------------------------------
385     */
386    
387     /* ARGSUSED */
388     static int
389     MarkDeleteProc(segPtr, linePtr, treeGone)
390     TkTextSegment *segPtr; /* Segment being deleted. */
391     TkTextLine *linePtr; /* Line containing segment. */
392     int treeGone; /* Non-zero means the entire tree is
393     * being deleted, so everything must
394     * get cleaned up. */
395     {
396     return 1;
397     }
398    
399     /*
400     *--------------------------------------------------------------
401     *
402     * MarkCleanupProc --
403     *
404     * This procedure is invoked by the B-tree code whenever a
405     * mark segment is moved from one line to another.
406     *
407     * Results:
408     * None.
409     *
410     * Side effects:
411     * The linePtr field of the segment gets updated.
412     *
413     *--------------------------------------------------------------
414     */
415    
416     static TkTextSegment *
417     MarkCleanupProc(markPtr, linePtr)
418     TkTextSegment *markPtr; /* Mark segment that's being moved. */
419     TkTextLine *linePtr; /* Line that now contains segment. */
420     {
421     markPtr->body.mark.linePtr = linePtr;
422     return markPtr;
423     }
424    
425     /*
426     *--------------------------------------------------------------
427     *
428     * MarkLayoutProc --
429     *
430     * This procedure is the "layoutProc" for mark segments.
431     *
432     * Results:
433     * If the mark isn't the insertion cursor then the return
434     * value is -1 to indicate that this segment shouldn't be
435     * displayed. If the mark is the insertion character then
436     * 1 is returned and the chunkPtr structure is filled in.
437     *
438     * Side effects:
439     * None, except for filling in chunkPtr.
440     *
441     *--------------------------------------------------------------
442     */
443    
444     /*ARGSUSED*/
445     static int
446     MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars,
447     noCharsYet, wrapMode, chunkPtr)
448     TkText *textPtr; /* Text widget being layed out. */
449     TkTextIndex *indexPtr; /* Identifies first character in chunk. */
450     TkTextSegment *segPtr; /* Segment corresponding to indexPtr. */
451     int offset; /* Offset within segPtr corresponding to
452     * indexPtr (always 0). */
453     int maxX; /* Chunk must not occupy pixels at this
454     * position or higher. */
455     int maxChars; /* Chunk must not include more than this
456     * many characters. */
457     int noCharsYet; /* Non-zero means no characters have been
458     * assigned to this line yet. */
459     TkWrapMode wrapMode; /* Not used. */
460     register TkTextDispChunk *chunkPtr;
461     /* Structure to fill in with information
462     * about this chunk. The x field has already
463     * been set by the caller. */
464     {
465     if (segPtr != textPtr->insertMarkPtr) {
466     return -1;
467     }
468    
469     chunkPtr->displayProc = TkTextInsertDisplayProc;
470     chunkPtr->undisplayProc = InsertUndisplayProc;
471     chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
472     chunkPtr->bboxProc = (Tk_ChunkBboxProc *) NULL;
473     chunkPtr->numBytes = 0;
474     chunkPtr->minAscent = 0;
475     chunkPtr->minDescent = 0;
476     chunkPtr->minHeight = 0;
477     chunkPtr->width = 0;
478    
479     /*
480     * Note: can't break a line after the insertion cursor: this
481     * prevents the insertion cursor from being stranded at the end
482     * of a line.
483     */
484    
485     chunkPtr->breakIndex = -1;
486     chunkPtr->clientData = (ClientData) textPtr;
487     return 1;
488     }
489    
490     /*
491     *--------------------------------------------------------------
492     *
493     * TkTextInsertDisplayProc --
494     *
495     * This procedure is called to display the insertion
496     * cursor.
497     *
498     * Results:
499     * None.
500     *
501     * Side effects:
502     * Graphics are drawn.
503     *
504     *--------------------------------------------------------------
505     */
506    
507     /* ARGSUSED */
508     void
509     TkTextInsertDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY)
510     TkTextDispChunk *chunkPtr; /* Chunk that is to be drawn. */
511     int x; /* X-position in dst at which to
512     * draw this chunk (may differ from
513     * the x-position in the chunk because
514     * of scrolling). */
515     int y; /* Y-position at which to draw this
516     * chunk in dst (x-position is in
517     * the chunk itself). */
518     int height; /* Total height of line. */
519     int baseline; /* Offset of baseline from y. */
520     Display *display; /* Display to use for drawing. */
521     Drawable dst; /* Pixmap or window in which to draw
522     * chunk. */
523     int screenY; /* Y-coordinate in text window that
524     * corresponds to y. */
525     {
526     TkText *textPtr = (TkText *) chunkPtr->clientData;
527     int halfWidth = textPtr->insertWidth/2;
528    
529     if ((x + halfWidth) < 0) {
530     /*
531     * The insertion cursor is off-screen. Just return.
532     */
533    
534     return;
535     }
536    
537     /*
538     * As a special hack to keep the cursor visible on mono displays
539     * (or anywhere else that the selection and insertion cursors
540     * have the same color) write the default background in the cursor
541     * area (instead of nothing) when the cursor isn't on. Otherwise
542     * the selection might hide the cursor.
543     */
544    
545     if (textPtr->flags & INSERT_ON) {
546     Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder,
547     x - textPtr->insertWidth/2, y, textPtr->insertWidth,
548     height, textPtr->insertBorderWidth, TK_RELIEF_RAISED);
549     } else if (textPtr->selBorder == textPtr->insertBorder) {
550     Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->border,
551     x - textPtr->insertWidth/2, y, textPtr->insertWidth,
552     height, 0, TK_RELIEF_FLAT);
553     }
554     }
555    
556     /*
557     *--------------------------------------------------------------
558     *
559     * InsertUndisplayProc --
560     *
561     * This procedure is called when the insertion cursor is no
562     * longer at a visible point on the display. It does nothing
563     * right now.
564     *
565     * Results:
566     * None.
567     *
568     * Side effects:
569     * None.
570     *
571     *--------------------------------------------------------------
572     */
573    
574     /* ARGSUSED */
575     static void
576     InsertUndisplayProc(textPtr, chunkPtr)
577     TkText *textPtr; /* Overall information about text
578     * widget. */
579     TkTextDispChunk *chunkPtr; /* Chunk that is about to be freed. */
580     {
581     return;
582     }
583    
584     /*
585     *--------------------------------------------------------------
586     *
587     * MarkCheckProc --
588     *
589     * This procedure is invoked by the B-tree code to perform
590     * consistency checks on mark segments.
591     *
592     * Results:
593     * None.
594     *
595     * Side effects:
596     * The procedure panics if it detects anything wrong with
597     * the mark.
598     *
599     *--------------------------------------------------------------
600     */
601    
602     static void
603     MarkCheckProc(markPtr, linePtr)
604     TkTextSegment *markPtr; /* Segment to check. */
605     TkTextLine *linePtr; /* Line containing segment. */
606     {
607     Tcl_HashSearch search;
608     Tcl_HashEntry *hPtr;
609    
610     if (markPtr->body.mark.linePtr != linePtr) {
611     panic("MarkCheckProc: markPtr->body.mark.linePtr bogus");
612     }
613    
614     /*
615     * Make sure that the mark is still present in the text's mark
616     * hash table.
617     */
618    
619     for (hPtr = Tcl_FirstHashEntry(&markPtr->body.mark.textPtr->markTable,
620     &search); hPtr != markPtr->body.mark.hPtr;
621     hPtr = Tcl_NextHashEntry(&search)) {
622     if (hPtr == NULL) {
623     panic("MarkCheckProc couldn't find hash table entry for mark");
624     }
625     }
626     }
627    
628     /*
629     *--------------------------------------------------------------
630     *
631     * MarkFindNext --
632     *
633     * This procedure searches forward for the next mark.
634     *
635     * Results:
636     * A standard Tcl result, which is a mark name or an empty string.
637     *
638     * Side effects:
639     * None.
640     *
641     *--------------------------------------------------------------
642     */
643    
644     static int
645     MarkFindNext(interp, textPtr, string)
646     Tcl_Interp *interp; /* For error reporting */
647     TkText *textPtr; /* The widget */
648     char *string; /* The starting index or mark name */
649     {
650     TkTextIndex index;
651     Tcl_HashEntry *hPtr;
652     register TkTextSegment *segPtr;
653     int offset;
654    
655    
656     hPtr = Tcl_FindHashEntry(&textPtr->markTable, string);
657     if (hPtr != NULL) {
658     /*
659     * If given a mark name, return the next mark in the list of
660     * segments, even if it happens to be at the same character position.
661     */
662     segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
663     TkTextMarkSegToIndex(textPtr, segPtr, &index);
664     segPtr = segPtr->nextPtr;
665     } else {
666     /*
667     * For non-mark name indices we want to return any marks that
668     * are right at the index.
669     */
670     if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) {
671     return TCL_ERROR;
672     }
673     for (offset = 0, segPtr = index.linePtr->segPtr;
674     segPtr != NULL && offset < index.byteIndex;
675     offset += segPtr->size, segPtr = segPtr->nextPtr) {
676     /* Empty loop body */ ;
677     }
678     }
679     while (1) {
680     /*
681     * segPtr points at the first possible candidate,
682     * or NULL if we ran off the end of the line.
683     */
684     for ( ; segPtr != NULL ; segPtr = segPtr->nextPtr) {
685     if (segPtr->typePtr == &tkTextRightMarkType ||
686     segPtr->typePtr == &tkTextLeftMarkType) {
687     Tcl_SetResult(interp,
688     Tcl_GetHashKey(&textPtr->markTable, segPtr->body.mark.hPtr),
689     TCL_STATIC);
690     return TCL_OK;
691     }
692     }
693     index.linePtr = TkBTreeNextLine(index.linePtr);
694     if (index.linePtr == (TkTextLine *) NULL) {
695     return TCL_OK;
696     }
697     index.byteIndex = 0;
698     segPtr = index.linePtr->segPtr;
699     }
700     }
701    
702     /*
703     *--------------------------------------------------------------
704     *
705     * MarkFindPrev --
706     *
707     * This procedure searches backwards for the previous mark.
708     *
709     * Results:
710     * A standard Tcl result, which is a mark name or an empty string.
711     *
712     * Side effects:
713     * None.
714     *
715     *--------------------------------------------------------------
716     */
717    
718     static int
719     MarkFindPrev(interp, textPtr, string)
720     Tcl_Interp *interp; /* For error reporting */
721     TkText *textPtr; /* The widget */
722     char *string; /* The starting index or mark name */
723     {
724     TkTextIndex index;
725     Tcl_HashEntry *hPtr;
726     register TkTextSegment *segPtr, *seg2Ptr, *prevPtr;
727     int offset;
728    
729    
730     hPtr = Tcl_FindHashEntry(&textPtr->markTable, string);
731     if (hPtr != NULL) {
732     /*
733     * If given a mark name, return the previous mark in the list of
734     * segments, even if it happens to be at the same character position.
735     */
736     segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
737     TkTextMarkSegToIndex(textPtr, segPtr, &index);
738     } else {
739     /*
740     * For non-mark name indices we do not return any marks that
741     * are right at the index.
742     */
743     if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) {
744     return TCL_ERROR;
745     }
746     for (offset = 0, segPtr = index.linePtr->segPtr;
747     segPtr != NULL && offset < index.byteIndex;
748     offset += segPtr->size, segPtr = segPtr->nextPtr) {
749     /* Empty loop body */ ;
750     }
751     }
752     while (1) {
753     /*
754     * segPtr points just past the first possible candidate,
755     * or at the begining of the line.
756     */
757     for (prevPtr = NULL, seg2Ptr = index.linePtr->segPtr;
758     seg2Ptr != NULL && seg2Ptr != segPtr;
759     seg2Ptr = seg2Ptr->nextPtr) {
760     if (seg2Ptr->typePtr == &tkTextRightMarkType ||
761     seg2Ptr->typePtr == &tkTextLeftMarkType) {
762     prevPtr = seg2Ptr;
763     }
764     }
765     if (prevPtr != NULL) {
766     Tcl_SetResult(interp,
767     Tcl_GetHashKey(&textPtr->markTable, prevPtr->body.mark.hPtr),
768     TCL_STATIC);
769     return TCL_OK;
770     }
771     index.linePtr = TkBTreePreviousLine(index.linePtr);
772     if (index.linePtr == (TkTextLine *) NULL) {
773     return TCL_OK;
774     }
775     segPtr = NULL;
776     }
777     }
778    
779 dashley 69 /* End of tktextmark.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25