tkTextMark.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:22k
- /*
- * tkTextMark.c --
- *
- * This file contains the procedure that implement marks for
- * text widgets.
- *
- * Copyright (c) 1994 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkTextMark.c,v 1.6 2002/08/05 04:30:40 dgp Exp $
- */
- #include "tkInt.h"
- #include "tkText.h"
- #include "tkPort.h"
- /*
- * Macro that determines the size of a mark segment:
- */
- #define MSEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body)
- + sizeof(TkTextMark)))
- /*
- * Forward references for procedures defined in this file:
- */
- static void InsertUndisplayProc _ANSI_ARGS_((TkText *textPtr,
- TkTextDispChunk *chunkPtr));
- static int MarkDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
- TkTextLine *linePtr, int treeGone));
- static TkTextSegment * MarkCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
- TkTextLine *linePtr));
- static void MarkCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
- TkTextLine *linePtr));
- static int MarkLayoutProc _ANSI_ARGS_((TkText *textPtr,
- TkTextIndex *indexPtr, TkTextSegment *segPtr,
- int offset, int maxX, int maxChars,
- int noCharsYet, TkWrapMode wrapMode,
- TkTextDispChunk *chunkPtr));
- static int MarkFindNext _ANSI_ARGS_((Tcl_Interp *interp,
- TkText *textPtr, CONST char *markName));
- static int MarkFindPrev _ANSI_ARGS_((Tcl_Interp *interp,
- TkText *textPtr, CONST char *markName));
- /*
- * The following structures declare the "mark" segment types.
- * There are actually two types for marks, one with left gravity
- * and one with right gravity. They are identical except for
- * their gravity property.
- */
- Tk_SegType tkTextRightMarkType = {
- "mark", /* name */
- 0, /* leftGravity */
- (Tk_SegSplitProc *) NULL, /* splitProc */
- MarkDeleteProc, /* deleteProc */
- MarkCleanupProc, /* cleanupProc */
- (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */
- MarkLayoutProc, /* layoutProc */
- MarkCheckProc /* checkProc */
- };
- Tk_SegType tkTextLeftMarkType = {
- "mark", /* name */
- 1, /* leftGravity */
- (Tk_SegSplitProc *) NULL, /* splitProc */
- MarkDeleteProc, /* deleteProc */
- MarkCleanupProc, /* cleanupProc */
- (Tk_SegLineChangeProc *) NULL, /* lineChangeProc */
- MarkLayoutProc, /* layoutProc */
- MarkCheckProc /* checkProc */
- };
- /*
- *--------------------------------------------------------------
- *
- * TkTextMarkCmd --
- *
- * This procedure is invoked to process the "mark" options of
- * the widget command for text widgets. See the user documentation
- * for details on what it does.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * See the user documentation.
- *
- *--------------------------------------------------------------
- */
- int
- TkTextMarkCmd(textPtr, interp, argc, argv)
- register TkText *textPtr; /* Information about text widget. */
- Tcl_Interp *interp; /* Current interpreter. */
- int argc; /* Number of arguments. */
- CONST char **argv; /* Argument strings. Someone else has already
- * parsed this command enough to know that
- * argv[1] is "mark". */
- {
- int c, i;
- size_t length;
- Tcl_HashEntry *hPtr;
- TkTextSegment *markPtr;
- Tcl_HashSearch search;
- TkTextIndex index;
- Tk_SegType *newTypePtr;
- if (argc < 3) {
- Tcl_AppendResult(interp, "wrong # args: should be "",
- argv[0], " mark option ?arg arg ...?"", (char *) NULL);
- return TCL_ERROR;
- }
- c = argv[2][0];
- length = strlen(argv[2]);
- if ((c == 'g') && (strncmp(argv[2], "gravity", length) == 0)) {
- if (argc < 4 || argc > 5) {
- Tcl_AppendResult(interp, "wrong # args: should be "",
- argv[0], " mark gravity markName ?gravity?"",
- (char *) NULL);
- return TCL_ERROR;
- }
- hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[3]);
- if (hPtr == NULL) {
- Tcl_AppendResult(interp, "there is no mark named "",
- argv[3], """, (char *) NULL);
- return TCL_ERROR;
- }
- markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
- if (argc == 4) {
- if (markPtr->typePtr == &tkTextRightMarkType) {
- Tcl_SetResult(interp, "right", TCL_STATIC);
- } else {
- Tcl_SetResult(interp, "left", TCL_STATIC);
- }
- return TCL_OK;
- }
- length = strlen(argv[4]);
- c = argv[4][0];
- if ((c == 'l') && (strncmp(argv[4], "left", length) == 0)) {
- newTypePtr = &tkTextLeftMarkType;
- } else if ((c == 'r') && (strncmp(argv[4], "right", length) == 0)) {
- newTypePtr = &tkTextRightMarkType;
- } else {
- Tcl_AppendResult(interp, "bad mark gravity "",
- argv[4], "": must be left or right", (char *) NULL);
- return TCL_ERROR;
- }
- TkTextMarkSegToIndex(textPtr, markPtr, &index);
- TkBTreeUnlinkSegment(textPtr->tree, markPtr,
- markPtr->body.mark.linePtr);
- markPtr->typePtr = newTypePtr;
- TkBTreeLinkSegment(markPtr, &index);
- } else if ((c == 'n') && (strncmp(argv[2], "names", length) == 0)) {
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be "",
- argv[0], " mark names"", (char *) NULL);
- return TCL_ERROR;
- }
- for (hPtr = Tcl_FirstHashEntry(&textPtr->markTable, &search);
- hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
- Tcl_AppendElement(interp,
- Tcl_GetHashKey(&textPtr->markTable, hPtr));
- }
- } else if ((c == 'n') && (strncmp(argv[2], "next", length) == 0)) {
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be "",
- argv[0], " mark next index"", (char *) NULL);
- return TCL_ERROR;
- }
- return MarkFindNext(interp, textPtr, argv[3]);
- } else if ((c == 'p') && (strncmp(argv[2], "previous", length) == 0)) {
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be "",
- argv[0], " mark previous index"", (char *) NULL);
- return TCL_ERROR;
- }
- return MarkFindPrev(interp, textPtr, argv[3]);
- } else if ((c == 's') && (strncmp(argv[2], "set", length) == 0)) {
- if (argc != 5) {
- Tcl_AppendResult(interp, "wrong # args: should be "",
- argv[0], " mark set markName index"", (char *) NULL);
- return TCL_ERROR;
- }
- if (TkTextGetIndex(interp, textPtr, argv[4], &index) != TCL_OK) {
- return TCL_ERROR;
- }
- TkTextSetMark(textPtr, argv[3], &index);
- } else if ((c == 'u') && (strncmp(argv[2], "unset", length) == 0)) {
- for (i = 3; i < argc; i++) {
- hPtr = Tcl_FindHashEntry(&textPtr->markTable, argv[i]);
- if (hPtr != NULL) {
- markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
- if ((markPtr == textPtr->insertMarkPtr)
- || (markPtr == textPtr->currentMarkPtr)) {
- continue;
- }
- TkBTreeUnlinkSegment(textPtr->tree, markPtr,
- markPtr->body.mark.linePtr);
- Tcl_DeleteHashEntry(hPtr);
- ckfree((char *) markPtr);
- }
- }
- } else {
- Tcl_AppendResult(interp, "bad mark option "", argv[2],
- "": must be gravity, names, next, previous, set, or unset",
- (char *) NULL);
- return TCL_ERROR;
- }
- return TCL_OK;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkTextSetMark --
- *
- * Set a mark to a particular position, creating a new mark if
- * one doesn't already exist.
- *
- * Results:
- * The return value is a pointer to the mark that was just set.
- *
- * Side effects:
- * A new mark is created, or an existing mark is moved.
- *
- *----------------------------------------------------------------------
- */
- TkTextSegment *
- TkTextSetMark(textPtr, name, indexPtr)
- TkText *textPtr; /* Text widget in which to create mark. */
- CONST char *name; /* Name of mark to set. */
- TkTextIndex *indexPtr; /* Where to set mark. */
- {
- Tcl_HashEntry *hPtr;
- TkTextSegment *markPtr;
- TkTextIndex insertIndex;
- int new;
- hPtr = Tcl_CreateHashEntry(&textPtr->markTable, name, &new);
- markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
- if (!new) {
- /*
- * If this is the insertion point that's being moved, be sure
- * to force a display update at the old position. Also, don't
- * let the insertion cursor be after the final newline of the
- * file.
- */
- if (markPtr == textPtr->insertMarkPtr) {
- TkTextIndex index, index2;
- TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index);
- TkTextIndexForwChars(&index, 1, &index2);
- TkTextChanged(textPtr, &index, &index2);
- if (TkBTreeLineIndex(indexPtr->linePtr)
- == TkBTreeNumLines(textPtr->tree)) {
- TkTextIndexBackChars(indexPtr, 1, &insertIndex);
- indexPtr = &insertIndex;
- }
- }
- TkBTreeUnlinkSegment(textPtr->tree, markPtr,
- markPtr->body.mark.linePtr);
- } else {
- markPtr = (TkTextSegment *) ckalloc(MSEG_SIZE);
- markPtr->typePtr = &tkTextRightMarkType;
- markPtr->size = 0;
- markPtr->body.mark.textPtr = textPtr;
- markPtr->body.mark.linePtr = indexPtr->linePtr;
- markPtr->body.mark.hPtr = hPtr;
- Tcl_SetHashValue(hPtr, markPtr);
- }
- TkBTreeLinkSegment(markPtr, indexPtr);
- /*
- * If the mark is the insertion cursor, then update the screen at the
- * mark's new location.
- */
- if (markPtr == textPtr->insertMarkPtr) {
- TkTextIndex index2;
- TkTextIndexForwChars(indexPtr, 1, &index2);
- TkTextChanged(textPtr, indexPtr, &index2);
- }
- return markPtr;
- }
- /*
- *--------------------------------------------------------------
- *
- * TkTextMarkSegToIndex --
- *
- * Given a segment that is a mark, create an index that
- * refers to the next text character (or other text segment
- * with non-zero size) after the mark.
- *
- * Results:
- * *IndexPtr is filled in with index information.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
- void
- TkTextMarkSegToIndex(textPtr, markPtr, indexPtr)
- TkText *textPtr; /* Text widget containing mark. */
- TkTextSegment *markPtr; /* Mark segment. */
- TkTextIndex *indexPtr; /* Index information gets stored here. */
- {
- TkTextSegment *segPtr;
- indexPtr->tree = textPtr->tree;
- indexPtr->linePtr = markPtr->body.mark.linePtr;
- indexPtr->byteIndex = 0;
- for (segPtr = indexPtr->linePtr->segPtr; segPtr != markPtr;
- segPtr = segPtr->nextPtr) {
- indexPtr->byteIndex += segPtr->size;
- }
- }
- /*
- *--------------------------------------------------------------
- *
- * TkTextMarkNameToIndex --
- *
- * Given the name of a mark, return an index corresponding
- * to the mark name.
- *
- * Results:
- * The return value is TCL_OK if "name" exists as a mark in
- * the text widget. In this case *indexPtr is filled in with
- * the next segment whose after the mark whose size is
- * non-zero. TCL_ERROR is returned if the mark doesn't exist
- * in the text widget.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
- int
- TkTextMarkNameToIndex(textPtr, name, indexPtr)
- TkText *textPtr; /* Text widget containing mark. */
- CONST char *name; /* Name of mark. */
- TkTextIndex *indexPtr; /* Index information gets stored here. */
- {
- Tcl_HashEntry *hPtr;
- hPtr = Tcl_FindHashEntry(&textPtr->markTable, name);
- if (hPtr == NULL) {
- return TCL_ERROR;
- }
- TkTextMarkSegToIndex(textPtr, (TkTextSegment *) Tcl_GetHashValue(hPtr),
- indexPtr);
- return TCL_OK;
- }
- /*
- *--------------------------------------------------------------
- *
- * MarkDeleteProc --
- *
- * This procedure is invoked by the text B-tree code whenever
- * a mark lies in a range of characters being deleted.
- *
- * Results:
- * Returns 1 to indicate that deletion has been rejected.
- *
- * Side effects:
- * None (even if the whole tree is being deleted we don't
- * free up the mark; it will be done elsewhere).
- *
- *--------------------------------------------------------------
- */
- /* ARGSUSED */
- static int
- MarkDeleteProc(segPtr, linePtr, treeGone)
- TkTextSegment *segPtr; /* Segment being deleted. */
- TkTextLine *linePtr; /* Line containing segment. */
- int treeGone; /* Non-zero means the entire tree is
- * being deleted, so everything must
- * get cleaned up. */
- {
- return 1;
- }
- /*
- *--------------------------------------------------------------
- *
- * MarkCleanupProc --
- *
- * This procedure is invoked by the B-tree code whenever a
- * mark segment is moved from one line to another.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The linePtr field of the segment gets updated.
- *
- *--------------------------------------------------------------
- */
- static TkTextSegment *
- MarkCleanupProc(markPtr, linePtr)
- TkTextSegment *markPtr; /* Mark segment that's being moved. */
- TkTextLine *linePtr; /* Line that now contains segment. */
- {
- markPtr->body.mark.linePtr = linePtr;
- return markPtr;
- }
- /*
- *--------------------------------------------------------------
- *
- * MarkLayoutProc --
- *
- * This procedure is the "layoutProc" for mark segments.
- *
- * Results:
- * If the mark isn't the insertion cursor then the return
- * value is -1 to indicate that this segment shouldn't be
- * displayed. If the mark is the insertion character then
- * 1 is returned and the chunkPtr structure is filled in.
- *
- * Side effects:
- * None, except for filling in chunkPtr.
- *
- *--------------------------------------------------------------
- */
- /*ARGSUSED*/
- static int
- MarkLayoutProc(textPtr, indexPtr, segPtr, offset, maxX, maxChars,
- noCharsYet, wrapMode, chunkPtr)
- TkText *textPtr; /* Text widget being layed out. */
- TkTextIndex *indexPtr; /* Identifies first character in chunk. */
- TkTextSegment *segPtr; /* Segment corresponding to indexPtr. */
- int offset; /* Offset within segPtr corresponding to
- * indexPtr (always 0). */
- int maxX; /* Chunk must not occupy pixels at this
- * position or higher. */
- int maxChars; /* Chunk must not include more than this
- * many characters. */
- int noCharsYet; /* Non-zero means no characters have been
- * assigned to this line yet. */
- TkWrapMode wrapMode; /* Not used. */
- register TkTextDispChunk *chunkPtr;
- /* Structure to fill in with information
- * about this chunk. The x field has already
- * been set by the caller. */
- {
- if (segPtr != textPtr->insertMarkPtr) {
- return -1;
- }
- chunkPtr->displayProc = TkTextInsertDisplayProc;
- chunkPtr->undisplayProc = InsertUndisplayProc;
- chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
- chunkPtr->bboxProc = (Tk_ChunkBboxProc *) NULL;
- chunkPtr->numBytes = 0;
- chunkPtr->minAscent = 0;
- chunkPtr->minDescent = 0;
- chunkPtr->minHeight = 0;
- chunkPtr->width = 0;
- /*
- * Note: can't break a line after the insertion cursor: this
- * prevents the insertion cursor from being stranded at the end
- * of a line.
- */
- chunkPtr->breakIndex = -1;
- chunkPtr->clientData = (ClientData) textPtr;
- return 1;
- }
- /*
- *--------------------------------------------------------------
- *
- * TkTextInsertDisplayProc --
- *
- * This procedure is called to display the insertion
- * cursor.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Graphics are drawn.
- *
- *--------------------------------------------------------------
- */
- /* ARGSUSED */
- void
- TkTextInsertDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY)
- TkTextDispChunk *chunkPtr; /* Chunk that is to be drawn. */
- int x; /* X-position in dst at which to
- * draw this chunk (may differ from
- * the x-position in the chunk because
- * of scrolling). */
- int y; /* Y-position at which to draw this
- * chunk in dst (x-position is in
- * the chunk itself). */
- int height; /* Total height of line. */
- int baseline; /* Offset of baseline from y. */
- Display *display; /* Display to use for drawing. */
- Drawable dst; /* Pixmap or window in which to draw
- * chunk. */
- int screenY; /* Y-coordinate in text window that
- * corresponds to y. */
- {
- TkText *textPtr = (TkText *) chunkPtr->clientData;
- int halfWidth = textPtr->insertWidth/2;
- if ((x + halfWidth) < 0) {
- /*
- * The insertion cursor is off-screen.
- * Indicate caret at 0,0 and return.
- */
- Tk_SetCaretPos(textPtr->tkwin, 0, 0, height);
- return;
- }
- Tk_SetCaretPos(textPtr->tkwin, x - halfWidth, screenY, height);
- /*
- * As a special hack to keep the cursor visible on mono displays
- * (or anywhere else that the selection and insertion cursors
- * have the same color) write the default background in the cursor
- * area (instead of nothing) when the cursor isn't on. Otherwise
- * the selection might hide the cursor.
- */
- if (textPtr->flags & INSERT_ON) {
- Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder,
- x - halfWidth, y, textPtr->insertWidth, height,
- textPtr->insertBorderWidth, TK_RELIEF_RAISED);
- } else if (textPtr->selBorder == textPtr->insertBorder) {
- Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->border,
- x - halfWidth, y, textPtr->insertWidth, height,
- 0, TK_RELIEF_FLAT);
- }
- }
- /*
- *--------------------------------------------------------------
- *
- * InsertUndisplayProc --
- *
- * This procedure is called when the insertion cursor is no
- * longer at a visible point on the display. It does nothing
- * right now.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
- /* ARGSUSED */
- static void
- InsertUndisplayProc(textPtr, chunkPtr)
- TkText *textPtr; /* Overall information about text
- * widget. */
- TkTextDispChunk *chunkPtr; /* Chunk that is about to be freed. */
- {
- return;
- }
- /*
- *--------------------------------------------------------------
- *
- * MarkCheckProc --
- *
- * This procedure is invoked by the B-tree code to perform
- * consistency checks on mark segments.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The procedure panics if it detects anything wrong with
- * the mark.
- *
- *--------------------------------------------------------------
- */
- static void
- MarkCheckProc(markPtr, linePtr)
- TkTextSegment *markPtr; /* Segment to check. */
- TkTextLine *linePtr; /* Line containing segment. */
- {
- Tcl_HashSearch search;
- Tcl_HashEntry *hPtr;
- if (markPtr->body.mark.linePtr != linePtr) {
- panic("MarkCheckProc: markPtr->body.mark.linePtr bogus");
- }
- /*
- * Make sure that the mark is still present in the text's mark
- * hash table.
- */
- for (hPtr = Tcl_FirstHashEntry(&markPtr->body.mark.textPtr->markTable,
- &search); hPtr != markPtr->body.mark.hPtr;
- hPtr = Tcl_NextHashEntry(&search)) {
- if (hPtr == NULL) {
- panic("MarkCheckProc couldn't find hash table entry for mark");
- }
- }
- }
- /*
- *--------------------------------------------------------------
- *
- * MarkFindNext --
- *
- * This procedure searches forward for the next mark.
- *
- * Results:
- * A standard Tcl result, which is a mark name or an empty string.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
- static int
- MarkFindNext(interp, textPtr, string)
- Tcl_Interp *interp; /* For error reporting */
- TkText *textPtr; /* The widget */
- CONST char *string; /* The starting index or mark name */
- {
- TkTextIndex index;
- Tcl_HashEntry *hPtr;
- register TkTextSegment *segPtr;
- int offset;
- hPtr = Tcl_FindHashEntry(&textPtr->markTable, string);
- if (hPtr != NULL) {
- /*
- * If given a mark name, return the next mark in the list of
- * segments, even if it happens to be at the same character position.
- */
- segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
- TkTextMarkSegToIndex(textPtr, segPtr, &index);
- segPtr = segPtr->nextPtr;
- } else {
- /*
- * For non-mark name indices we want to return any marks that
- * are right at the index.
- */
- if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) {
- return TCL_ERROR;
- }
- for (offset = 0, segPtr = index.linePtr->segPtr;
- segPtr != NULL && offset < index.byteIndex;
- offset += segPtr->size, segPtr = segPtr->nextPtr) {
- /* Empty loop body */ ;
- }
- }
- while (1) {
- /*
- * segPtr points at the first possible candidate,
- * or NULL if we ran off the end of the line.
- */
- for ( ; segPtr != NULL ; segPtr = segPtr->nextPtr) {
- if (segPtr->typePtr == &tkTextRightMarkType ||
- segPtr->typePtr == &tkTextLeftMarkType) {
- Tcl_SetResult(interp,
- Tcl_GetHashKey(&textPtr->markTable, segPtr->body.mark.hPtr),
- TCL_STATIC);
- return TCL_OK;
- }
- }
- index.linePtr = TkBTreeNextLine(index.linePtr);
- if (index.linePtr == (TkTextLine *) NULL) {
- return TCL_OK;
- }
- index.byteIndex = 0;
- segPtr = index.linePtr->segPtr;
- }
- }
- /*
- *--------------------------------------------------------------
- *
- * MarkFindPrev --
- *
- * This procedure searches backwards for the previous mark.
- *
- * Results:
- * A standard Tcl result, which is a mark name or an empty string.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
- static int
- MarkFindPrev(interp, textPtr, string)
- Tcl_Interp *interp; /* For error reporting */
- TkText *textPtr; /* The widget */
- CONST char *string; /* The starting index or mark name */
- {
- TkTextIndex index;
- Tcl_HashEntry *hPtr;
- register TkTextSegment *segPtr, *seg2Ptr, *prevPtr;
- int offset;
- hPtr = Tcl_FindHashEntry(&textPtr->markTable, string);
- if (hPtr != NULL) {
- /*
- * If given a mark name, return the previous mark in the list of
- * segments, even if it happens to be at the same character position.
- */
- segPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
- TkTextMarkSegToIndex(textPtr, segPtr, &index);
- } else {
- /*
- * For non-mark name indices we do not return any marks that
- * are right at the index.
- */
- if (TkTextGetIndex(interp, textPtr, string, &index) != TCL_OK) {
- return TCL_ERROR;
- }
- for (offset = 0, segPtr = index.linePtr->segPtr;
- segPtr != NULL && offset < index.byteIndex;
- offset += segPtr->size, segPtr = segPtr->nextPtr) {
- /* Empty loop body */ ;
- }
- }
- while (1) {
- /*
- * segPtr points just past the first possible candidate,
- * or at the begining of the line.
- */
- for (prevPtr = NULL, seg2Ptr = index.linePtr->segPtr;
- seg2Ptr != NULL && seg2Ptr != segPtr;
- seg2Ptr = seg2Ptr->nextPtr) {
- if (seg2Ptr->typePtr == &tkTextRightMarkType ||
- seg2Ptr->typePtr == &tkTextLeftMarkType) {
- prevPtr = seg2Ptr;
- }
- }
- if (prevPtr != NULL) {
- Tcl_SetResult(interp,
- Tcl_GetHashKey(&textPtr->markTable, prevPtr->body.mark.hPtr),
- TCL_STATIC);
- return TCL_OK;
- }
- index.linePtr = TkBTreePreviousLine(index.linePtr);
- if (index.linePtr == (TkTextLine *) NULL) {
- return TCL_OK;
- }
- segPtr = NULL;
- }
- }