📄 tktextindex.c
字号:
/* * tkTextIndex.c -- * * This module provides procedures that manipulate indices for * text widgets. * * Copyright (c) 1992-1994 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkTextIndex.c 1.15 97/06/17 17:49:24 */#include "default.h"#include "tkPort.h"#include "tkInt.h"#include "tkText.h"/* * Index to use to select last character in line (very large integer): */#define LAST_CHAR 1000000/* * Forward declarations for procedures defined later in this file: */static char * ForwBack _ANSI_ARGS_((char *string, TkTextIndex *indexPtr));static char * StartEnd _ANSI_ARGS_(( char *string, TkTextIndex *indexPtr));/* *-------------------------------------------------------------- * * TkTextMakeIndex -- * * Given a line index and a character index, look things up * in the B-tree and fill in a TkTextIndex structure. * * Results: * The structure at *indexPtr is filled in with information * about the character at lineIndex and charIndex (or the * closest existing character, if the specified one doesn't * exist), and indexPtr is returned as result. * * Side effects: * None. * *-------------------------------------------------------------- */TkTextIndex *TkTextMakeIndex(tree, lineIndex, charIndex, indexPtr) TkTextBTree tree; /* Tree that lineIndex and charIndex refer * to. */ int lineIndex; /* Index of desired line (0 means first * line of text). */ int charIndex; /* Index of desired character. */ TkTextIndex *indexPtr; /* Structure to fill in. */{ register TkTextSegment *segPtr; int index; indexPtr->tree = tree; if (lineIndex < 0) { lineIndex = 0; charIndex = 0; } if (charIndex < 0) { charIndex = 0; } indexPtr->linePtr = TkBTreeFindLine(tree, lineIndex); if (indexPtr->linePtr == NULL) { indexPtr->linePtr = TkBTreeFindLine(tree, TkBTreeNumLines(tree)); charIndex = 0; } /* * Verify that the index is within the range of the line. * If not, just use the index of the last character in the line. */ for (index = 0, segPtr = indexPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) { if (segPtr == NULL) { indexPtr->charIndex = index-1; break; } index += segPtr->size; if (index > charIndex) { indexPtr->charIndex = charIndex; break; } } return indexPtr;}/* *-------------------------------------------------------------- * * TkTextIndexToSeg -- * * Given an index, this procedure returns the segment and * offset within segment for the index. * * Results: * The return value is a pointer to the segment referred to * by indexPtr; this will always be a segment with non-zero * size. The variable at *offsetPtr is set to hold the * integer offset within the segment of the character * given by indexPtr. * * Side effects: * None. * *-------------------------------------------------------------- */TkTextSegment *TkTextIndexToSeg(indexPtr, offsetPtr) TkTextIndex *indexPtr; /* Text index. */ int *offsetPtr; /* Where to store offset within * segment, or NULL if offset isn't * wanted. */{ register TkTextSegment *segPtr; int offset; for (offset = indexPtr->charIndex, segPtr = indexPtr->linePtr->segPtr; offset >= segPtr->size; offset -= segPtr->size, segPtr = segPtr->nextPtr) { /* Empty loop body. */ } if (offsetPtr != NULL) { *offsetPtr = offset; } return segPtr;}/* *-------------------------------------------------------------- * * TkTextSegToOffset -- * * Given a segment pointer and the line containing it, this * procedure returns the offset of the segment within its * line. * * Results: * The return value is the offset (within its line) of the * first character in segPtr. * * Side effects: * None. * *-------------------------------------------------------------- */intTkTextSegToOffset(segPtr, linePtr) TkTextSegment *segPtr; /* Segment whose offset is desired. */ TkTextLine *linePtr; /* Line containing segPtr. */{ TkTextSegment *segPtr2; int offset; offset = 0; for (segPtr2 = linePtr->segPtr; segPtr2 != segPtr; segPtr2 = segPtr2->nextPtr) { offset += segPtr2->size; } return offset;}/* *---------------------------------------------------------------------- * * TkTextGetIndex -- * * Given a string, return the line and character indices that * it describes. * * Results: * The return value is a standard Tcl return result. If * TCL_OK is returned, then everything went well and the index * at *indexPtr is filled in; otherwise TCL_ERROR is returned * and an error message is left in interp->result. * * Side effects: * None. * *---------------------------------------------------------------------- */intTkTextGetIndex(interp, textPtr, string, indexPtr) Tcl_Interp *interp; /* Use this for error reporting. */ TkText *textPtr; /* Information about text widget. */ char *string; /* Textual description of position. */ TkTextIndex *indexPtr; /* Index structure to fill in. */{ register char *p; char *end, *endOfBase; Tcl_HashEntry *hPtr; TkTextTag *tagPtr; TkTextSearch search; TkTextIndex first, last; int wantLast, result; char c; /* *--------------------------------------------------------------------- * Stage 1: check to see if the index consists of nothing but a mark * name. We do this check now even though it's also done later, in * order to allow mark names that include funny characters such as * spaces or "+1c". *--------------------------------------------------------------------- */ if (TkTextMarkNameToIndex(textPtr, string, indexPtr) == TCL_OK) { return TCL_OK; } /* *------------------------------------------------ * Stage 2: start again by parsing the base index. *------------------------------------------------ */ indexPtr->tree = textPtr->tree; /* * First look for the form "tag.first" or "tag.last" where "tag" * is the name of a valid tag. Try to use up as much as possible * of the string in this check (strrchr instead of strchr below). * Doing the check now, and in this way, allows tag names to include * funny characters like "@" or "+1c". */ p = strrchr(string, '.'); if (p != NULL) { if ((p[1] == 'f') && (strncmp(p+1, "first", 5) == 0)) { wantLast = 0; endOfBase = p+6; } else if ((p[1] == 'l') && (strncmp(p+1, "last", 4) == 0)) { wantLast = 1; endOfBase = p+5; } else { goto tryxy; } *p = 0; hPtr = Tcl_FindHashEntry(&textPtr->tagTable, string); *p = '.'; if (hPtr == NULL) { goto tryxy; } tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); TkTextMakeIndex(textPtr->tree, 0, 0, &first); TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, &last); TkBTreeStartSearch(&first, &last, tagPtr, &search); if (!TkBTreeCharTagged(&first, tagPtr) && !TkBTreeNextTag(&search)) { Tcl_AppendResult(interp, "text doesn't contain any characters tagged with \"", Tcl_GetHashKey(&textPtr->tagTable, hPtr), "\"", (char *) NULL); return TCL_ERROR; } *indexPtr = search.curIndex; if (wantLast) { while (TkBTreeNextTag(&search)) { *indexPtr = search.curIndex; } } goto gotBase; } tryxy: if (string[0] == '@') { /* * Find character at a given x,y location in the window. */ int x, y; p = string+1; x = strtol(p, &end, 0); if ((end == p) || (*end != ',')) { goto error; } p = end+1; y = strtol(p, &end, 0); if (end == p) { goto error; } TkTextPixelIndex(textPtr, x, y, indexPtr); endOfBase = end; goto gotBase; } if (isdigit(UCHAR(string[0])) || (string[0] == '-')) { int lineIndex, charIndex; /* * Base is identified with line and character indices. */ lineIndex = strtol(string, &end, 0) - 1; if ((end == string) || (*end != '.')) { goto error; } p = end+1; if ((*p == 'e') && (strncmp(p, "end", 3) == 0)) { charIndex = LAST_CHAR; endOfBase = p+3; } else { charIndex = strtol(p, &end, 0); if (end == p) { goto error; } endOfBase = end; } TkTextMakeIndex(textPtr->tree, lineIndex, charIndex, indexPtr); goto gotBase; } for (p = string; *p != 0; p++) { if (isspace(UCHAR(*p)) || (*p == '+') || (*p == '-')) { break; } } endOfBase = p; if (string[0] == '.') { /* * See if the base position is the name of an embedded window. */ c = *endOfBase; *endOfBase = 0; result = TkTextWindowIndex(textPtr, string, indexPtr); *endOfBase = c; if (result != 0) { goto gotBase; } } if ((string[0] == 'e') && (strncmp(string, "end", (size_t) (endOfBase-string)) == 0)) { /* * Base position is end of text. */ TkTextMakeIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0, indexPtr); goto gotBase; } else { /* * See if the base position is the name of a mark. */ c = *endOfBase; *endOfBase = 0; result = TkTextMarkNameToIndex(textPtr, string, indexPtr); *endOfBase = c; if (result == TCL_OK) { goto gotBase; } /* * See if the base position is the name of an embedded image */ c = *endOfBase; *endOfBase = 0; result = TkTextImageIndex(textPtr, string, indexPtr); *endOfBase = c; if (result != 0) { goto gotBase; } } goto error; /* *------------------------------------------------------------------- * Stage 3: process zero or more modifiers. Each modifier is either * a keyword like "wordend" or "linestart", or it has the form * "op count units" where op is + or -, count is a number, and units * is "chars" or "lines". *------------------------------------------------------------------- */ gotBase: p = endOfBase; while (1) { while (isspace(UCHAR(*p))) { p++; } if (*p == 0) { break; } if ((*p == '+') || (*p == '-')) { p = ForwBack(p, indexPtr); } else { p = StartEnd(p, indexPtr); } if (p == NULL) { goto error; } } return TCL_OK; error: Tcl_AppendResult(interp, "bad text index \"", string, "\"", (char *) NULL); return TCL_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -