4 * This module provides procedures that manipulate indices for
7 * Copyright (c) 1992-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22 * Index to use to select last character in line (very large integer):
25 #define LAST_CHAR 1000000
28 * Forward declarations for procedures defined later in this file:
31 static char * ForwBack _ANSI_ARGS_((char *string,
32 TkTextIndex *indexPtr));
33 static char * StartEnd _ANSI_ARGS_(( char *string,
34 TkTextIndex *indexPtr));
37 *---------------------------------------------------------------------------
39 * TkTextMakeByteIndex --
41 * Given a line index and a byte index, look things up in the B-tree
42 * and fill in a TkTextIndex structure.
45 * The structure at *indexPtr is filled in with information about the
46 * character at lineIndex and byteIndex (or the closest existing
47 * character, if the specified one doesn't exist), and indexPtr is
53 *---------------------------------------------------------------------------
57 TkTextMakeByteIndex(tree, lineIndex, byteIndex, indexPtr)
58 TkTextBTree tree; /* Tree that lineIndex and charIndex refer
60 int lineIndex; /* Index of desired line (0 means first
62 int byteIndex; /* Byte index of desired character. */
63 TkTextIndex *indexPtr; /* Structure to fill in. */
65 TkTextSegment *segPtr;
70 indexPtr->tree = tree;
78 indexPtr->linePtr = TkBTreeFindLine(tree, lineIndex);
79 if (indexPtr->linePtr == NULL) {
80 indexPtr->linePtr = TkBTreeFindLine(tree, TkBTreeNumLines(tree));
84 indexPtr->byteIndex = byteIndex;
89 * Verify that the index is within the range of the line and points
90 * to a valid character boundary.
94 for (segPtr = indexPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) {
97 * Use the index of the last character in the line. Since
98 * the last character on the line is guaranteed to be a '\n',
99 * we can back up a constant sizeof(char) bytes.
102 indexPtr->byteIndex = index - sizeof(char);
105 if (index + segPtr->size > byteIndex) {
106 indexPtr->byteIndex = byteIndex;
107 if ((byteIndex > index) && (segPtr->typePtr == &tkTextCharType)) {
109 * Prevent UTF-8 character from being split up by ensuring
110 * that byteIndex falls on a character boundary. If index
111 * falls in the middle of a UTF-8 character, it will be
112 * adjusted to the end of that UTF-8 character.
115 start = segPtr->body.chars + (byteIndex - index);
116 p = Tcl_UtfPrev(start, segPtr->body.chars);
117 p += Tcl_UtfToUniChar(p, &ch);
118 indexPtr->byteIndex += p - start;
122 index += segPtr->size;
128 *---------------------------------------------------------------------------
130 * TkTextMakeCharIndex --
132 * Given a line index and a character index, look things up in the
133 * B-tree and fill in a TkTextIndex structure.
136 * The structure at *indexPtr is filled in with information about the
137 * character at lineIndex and charIndex (or the closest existing
138 * character, if the specified one doesn't exist), and indexPtr is
139 * returned as result.
144 *---------------------------------------------------------------------------
148 TkTextMakeCharIndex(tree, lineIndex, charIndex, indexPtr)
149 TkTextBTree tree; /* Tree that lineIndex and charIndex refer
151 int lineIndex; /* Index of desired line (0 means first
153 int charIndex; /* Index of desired character. */
154 TkTextIndex *indexPtr; /* Structure to fill in. */
156 register TkTextSegment *segPtr;
157 char *p, *start, *end;
161 indexPtr->tree = tree;
169 indexPtr->linePtr = TkBTreeFindLine(tree, lineIndex);
170 if (indexPtr->linePtr == NULL) {
171 indexPtr->linePtr = TkBTreeFindLine(tree, TkBTreeNumLines(tree));
176 * Verify that the index is within the range of the line.
177 * If not, just use the index of the last character in the line.
181 for (segPtr = indexPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) {
182 if (segPtr == NULL) {
184 * Use the index of the last character in the line. Since
185 * the last character on the line is guaranteed to be a '\n',
186 * we can back up a constant sizeof(char) bytes.
189 indexPtr->byteIndex = index - sizeof(char);
192 if (segPtr->typePtr == &tkTextCharType) {
194 * Turn character offset into a byte offset.
197 start = segPtr->body.chars;
198 end = start + segPtr->size;
199 for (p = start; p < end; p += offset) {
200 if (charIndex == 0) {
201 indexPtr->byteIndex = index;
205 offset = Tcl_UtfToUniChar(p, &ch);
209 if (charIndex < segPtr->size) {
210 indexPtr->byteIndex = index;
213 charIndex -= segPtr->size;
214 index += segPtr->size;
221 *---------------------------------------------------------------------------
223 * TkTextIndexToSeg --
225 * Given an index, this procedure returns the segment and offset
226 * within segment for the index.
229 * The return value is a pointer to the segment referred to by
230 * indexPtr; this will always be a segment with non-zero size. The
231 * variable at *offsetPtr is set to hold the integer offset within
232 * the segment of the character given by indexPtr.
237 *---------------------------------------------------------------------------
241 TkTextIndexToSeg(indexPtr, offsetPtr)
242 CONST TkTextIndex *indexPtr;/* Text index. */
243 int *offsetPtr; /* Where to store offset within segment, or
244 * NULL if offset isn't wanted. */
246 TkTextSegment *segPtr;
249 for (offset = indexPtr->byteIndex, segPtr = indexPtr->linePtr->segPtr;
250 offset >= segPtr->size;
251 offset -= segPtr->size, segPtr = segPtr->nextPtr) {
252 /* Empty loop body. */
254 if (offsetPtr != NULL) {
261 *---------------------------------------------------------------------------
263 * TkTextSegToOffset --
265 * Given a segment pointer and the line containing it, this procedure
266 * returns the offset of the segment within its line.
269 * The return value is the offset (within its line) of the first
270 * character in segPtr.
275 *---------------------------------------------------------------------------
279 TkTextSegToOffset(segPtr, linePtr)
280 CONST TkTextSegment *segPtr;/* Segment whose offset is desired. */
281 CONST TkTextLine *linePtr; /* Line containing segPtr. */
283 CONST TkTextSegment *segPtr2;
287 for (segPtr2 = linePtr->segPtr; segPtr2 != segPtr;
288 segPtr2 = segPtr2->nextPtr) {
289 offset += segPtr2->size;
295 *---------------------------------------------------------------------------
299 * Given a string, return the index that is described.
302 * The return value is a standard Tcl return result. If TCL_OK is
303 * returned, then everything went well and the index at *indexPtr is
304 * filled in; otherwise TCL_ERROR is returned and an error message
305 * is left in the interp's result.
310 *---------------------------------------------------------------------------
314 TkTextGetIndex(interp, textPtr, string, indexPtr)
315 Tcl_Interp *interp; /* Use this for error reporting. */
316 TkText *textPtr; /* Information about text widget. */
317 char *string; /* Textual description of position. */
318 TkTextIndex *indexPtr; /* Index structure to fill in. */
320 char *p, *end, *endOfBase;
324 TkTextIndex first, last;
325 int wantLast, result;
329 *---------------------------------------------------------------------
330 * Stage 1: check to see if the index consists of nothing but a mark
331 * name. We do this check now even though it's also done later, in
332 * order to allow mark names that include funny characters such as
334 *---------------------------------------------------------------------
337 if (TkTextMarkNameToIndex(textPtr, string, indexPtr) == TCL_OK) {
342 *------------------------------------------------
343 * Stage 2: start again by parsing the base index.
344 *------------------------------------------------
347 indexPtr->tree = textPtr->tree;
350 * First look for the form "tag.first" or "tag.last" where "tag"
351 * is the name of a valid tag. Try to use up as much as possible
352 * of the string in this check (strrchr instead of strchr below).
353 * Doing the check now, and in this way, allows tag names to include
354 * funny characters like "@" or "+1c".
357 p = strrchr(string, '.');
359 if ((p[1] == 'f') && (strncmp(p+1, "first", 5) == 0)) {
362 } else if ((p[1] == 'l') && (strncmp(p+1, "last", 4) == 0)) {
369 hPtr = Tcl_FindHashEntry(&textPtr->tagTable, string);
374 tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr);
375 TkTextMakeByteIndex(textPtr->tree, 0, 0, &first);
376 TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree), 0,
378 TkBTreeStartSearch(&first, &last, tagPtr, &search);
379 if (!TkBTreeCharTagged(&first, tagPtr) && !TkBTreeNextTag(&search)) {
380 Tcl_AppendResult(interp,
381 "text doesn't contain any characters tagged with \"",
382 Tcl_GetHashKey(&textPtr->tagTable, hPtr), "\"",
386 *indexPtr = search.curIndex;
388 while (TkBTreeNextTag(&search)) {
389 *indexPtr = search.curIndex;
396 if (string[0] == '@') {
398 * Find character at a given x,y location in the window.
404 x = strtol(p, &end, 0);
405 if ((end == p) || (*end != ',')) {
409 y = strtol(p, &end, 0);
413 TkTextPixelIndex(textPtr, x, y, indexPtr);
418 if (isdigit(UCHAR(string[0])) || (string[0] == '-')) {
419 int lineIndex, charIndex;
422 * Base is identified with line and character indices.
425 lineIndex = strtol(string, &end, 0) - 1;
426 if ((end == string) || (*end != '.')) {
430 if ((*p == 'e') && (strncmp(p, "end", 3) == 0)) {
431 charIndex = LAST_CHAR;
434 charIndex = strtol(p, &end, 0);
440 TkTextMakeCharIndex(textPtr->tree, lineIndex, charIndex, indexPtr);
444 for (p = string; *p != 0; p++) {
445 if (isspace(UCHAR(*p)) || (*p == '+') || (*p == '-')) {
450 if (string[0] == '.') {
452 * See if the base position is the name of an embedded window.
457 result = TkTextWindowIndex(textPtr, string, indexPtr);
463 if ((string[0] == 'e')
464 && (strncmp(string, "end", (size_t) (endOfBase-string)) == 0)) {
466 * Base position is end of text.
469 TkTextMakeByteIndex(textPtr->tree, TkBTreeNumLines(textPtr->tree),
474 * See if the base position is the name of a mark.
479 result = TkTextMarkNameToIndex(textPtr, string, indexPtr);
481 if (result == TCL_OK) {
486 * See if the base position is the name of an embedded image
491 result = TkTextImageIndex(textPtr, string, indexPtr);
500 *-------------------------------------------------------------------
501 * Stage 3: process zero or more modifiers. Each modifier is either
502 * a keyword like "wordend" or "linestart", or it has the form
503 * "op count units" where op is + or -, count is a number, and units
504 * is "chars" or "lines".
505 *-------------------------------------------------------------------
511 while (isspace(UCHAR(*p))) {
518 if ((*p == '+') || (*p == '-')) {
519 p = ForwBack(p, indexPtr);
521 p = StartEnd(p, indexPtr);
530 Tcl_AppendResult(interp, "bad text index \"", string, "\"",
536 *---------------------------------------------------------------------------
538 * TkTextPrintIndex --
540 * This procedure generates a string description of an index, suitable
541 * for reading in again later.
544 * The characters pointed to by string are modified.
549 *---------------------------------------------------------------------------
553 TkTextPrintIndex(indexPtr, string)
554 CONST TkTextIndex *indexPtr;/* Pointer to index. */
555 char *string; /* Place to store the position. Must have
556 * at least TK_POS_CHARS characters. */
558 TkTextSegment *segPtr;
559 int numBytes, charIndex;
561 numBytes = indexPtr->byteIndex;
563 for (segPtr = indexPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) {
564 if (numBytes <= segPtr->size) {
567 if (segPtr->typePtr == &tkTextCharType) {
568 charIndex += Tcl_NumUtfChars(segPtr->body.chars, segPtr->size);
570 charIndex += segPtr->size;
572 numBytes -= segPtr->size;
574 if (segPtr->typePtr == &tkTextCharType) {
575 charIndex += Tcl_NumUtfChars(segPtr->body.chars, numBytes);
577 charIndex += numBytes;
579 sprintf(string, "%d.%d", TkBTreeLineIndex(indexPtr->linePtr) + 1,
584 *---------------------------------------------------------------------------
588 * Compare two indices to see which one is earlier in the text.
591 * The return value is 0 if index1Ptr and index2Ptr refer to the same
592 * position in the file, -1 if index1Ptr refers to an earlier position
593 * than index2Ptr, and 1 otherwise.
598 *---------------------------------------------------------------------------
602 TkTextIndexCmp(index1Ptr, index2Ptr)
603 CONST TkTextIndex *index1Ptr; /* First index. */
604 CONST TkTextIndex *index2Ptr; /* Second index. */
608 if (index1Ptr->linePtr == index2Ptr->linePtr) {
609 if (index1Ptr->byteIndex < index2Ptr->byteIndex) {
611 } else if (index1Ptr->byteIndex > index2Ptr->byteIndex) {
617 line1 = TkBTreeLineIndex(index1Ptr->linePtr);
618 line2 = TkBTreeLineIndex(index2Ptr->linePtr);
629 *---------------------------------------------------------------------------
633 * This procedure handles +/- modifiers for indices to adjust the
634 * index forwards or backwards.
637 * If the modifier in string is successfully parsed then the return
638 * value is the address of the first character after the modifier,
639 * and *indexPtr is updated to reflect the modifier. If there is a
640 * syntax error in the modifier then NULL is returned.
645 *---------------------------------------------------------------------------
649 ForwBack(string, indexPtr)
650 char *string; /* String to parse for additional info
651 * about modifier (count and units).
652 * Points to "+" or "-" that starts
654 TkTextIndex *indexPtr; /* Index to update as specified in string. */
658 int count, lineIndex;
662 * Get the count (how many units forward or backward).
666 while (isspace(UCHAR(*p))) {
669 count = strtol(p, &end, 0);
674 while (isspace(UCHAR(*p))) {
679 * Find the end of this modifier (next space or + or - character),
680 * then parse the unit specifier and update the position
685 while ((*p != '\0') && !isspace(UCHAR(*p)) && (*p != '+') && (*p != '-')) {
689 if ((*units == 'c') && (strncmp(units, "chars", length) == 0)) {
690 if (*string == '+') {
691 TkTextIndexForwChars(indexPtr, count, indexPtr);
693 TkTextIndexBackChars(indexPtr, count, indexPtr);
695 } else if ((*units == 'l') && (strncmp(units, "lines", length) == 0)) {
696 lineIndex = TkBTreeLineIndex(indexPtr->linePtr);
697 if (*string == '+') {
703 * The check below retains the character position, even
704 * if the line runs off the start of the file. Without
705 * it, the character position will get reset to 0 by
714 * This doesn't work quite right if using a proportional font or
715 * UTF-8 characters with varying numbers of bytes. The cursor will
716 * bop around, keeping a constant number of bytes (not characters)
717 * from the left edge (but making sure not to split any UTF-8
718 * characters), regardless of the x-position the index corresponds
719 * to. The proper way to do this is to get the x-position of the
720 * index and then pick the character at the same x-position in the
724 TkTextMakeByteIndex(indexPtr->tree, lineIndex, indexPtr->byteIndex,
733 *---------------------------------------------------------------------------
735 * TkTextIndexForwBytes --
737 * Given an index for a text widget, this procedure creates a new
738 * index that points "count" bytes ahead of the source index.
741 * *dstPtr is modified to refer to the character "count" bytes after
742 * srcPtr, or to the last character in the TkText if there aren't
743 * "count" bytes left.
748 *---------------------------------------------------------------------------
752 TkTextIndexForwBytes(srcPtr, byteCount, dstPtr)
753 CONST TkTextIndex *srcPtr; /* Source index. */
754 int byteCount; /* How many bytes forward to move. May be
756 TkTextIndex *dstPtr; /* Destination index: gets modified. */
759 TkTextSegment *segPtr;
763 TkTextIndexBackBytes(srcPtr, -byteCount, dstPtr);
768 dstPtr->byteIndex += byteCount;
771 * Compute the length of the current line.
775 for (segPtr = dstPtr->linePtr->segPtr; segPtr != NULL;
776 segPtr = segPtr->nextPtr) {
777 lineLength += segPtr->size;
781 * If the new index is in the same line then we're done.
782 * Otherwise go on to the next line.
785 if (dstPtr->byteIndex < lineLength) {
788 dstPtr->byteIndex -= lineLength;
789 linePtr = TkBTreeNextLine(dstPtr->linePtr);
790 if (linePtr == NULL) {
791 dstPtr->byteIndex = lineLength - 1;
794 dstPtr->linePtr = linePtr;
799 *---------------------------------------------------------------------------
801 * TkTextIndexForwChars --
803 * Given an index for a text widget, this procedure creates a new
804 * index that points "count" characters ahead of the source index.
807 * *dstPtr is modified to refer to the character "count" characters
808 * after srcPtr, or to the last character in the TkText if there
809 * aren't "count" characters left in the file.
814 *---------------------------------------------------------------------------
818 TkTextIndexForwChars(srcPtr, charCount, dstPtr)
819 CONST TkTextIndex *srcPtr; /* Source index. */
820 int charCount; /* How many characters forward to move.
821 * May be negative. */
822 TkTextIndex *dstPtr; /* Destination index: gets modified. */
825 TkTextSegment *segPtr;
827 char *start, *end, *p;
831 TkTextIndexBackChars(srcPtr, -charCount, dstPtr);
838 * Find seg that contains src byteIndex.
839 * Move forward specified number of chars.
842 segPtr = TkTextIndexToSeg(dstPtr, &byteOffset);
845 * Go through each segment in line looking for specified character
849 for ( ; segPtr != NULL; segPtr = segPtr->nextPtr) {
850 if (segPtr->typePtr == &tkTextCharType) {
851 start = segPtr->body.chars + byteOffset;
852 end = segPtr->body.chars + segPtr->size;
853 for (p = start; p < end; p += Tcl_UtfToUniChar(p, &ch)) {
854 if (charCount == 0) {
855 dstPtr->byteIndex += (p - start);
861 if (charCount < segPtr->size - byteOffset) {
862 dstPtr->byteIndex += charCount;
865 charCount -= segPtr->size - byteOffset;
867 dstPtr->byteIndex += segPtr->size - byteOffset;
872 * Go to the next line. If we are at the end of the text item,
873 * back up one byte (for the terminal '\n' character) and return
877 linePtr = TkBTreeNextLine(dstPtr->linePtr);
878 if (linePtr == NULL) {
879 dstPtr->byteIndex -= sizeof(char);
882 dstPtr->linePtr = linePtr;
883 dstPtr->byteIndex = 0;
884 segPtr = dstPtr->linePtr->segPtr;
889 *---------------------------------------------------------------------------
891 * TkTextIndexBackBytes --
893 * Given an index for a text widget, this procedure creates a new
894 * index that points "count" bytes earlier than the source index.
897 * *dstPtr is modified to refer to the character "count" bytes before
898 * srcPtr, or to the first character in the TkText if there aren't
899 * "count" bytes earlier than srcPtr.
904 *---------------------------------------------------------------------------
908 TkTextIndexBackBytes(srcPtr, byteCount, dstPtr)
909 CONST TkTextIndex *srcPtr; /* Source index. */
910 int byteCount; /* How many bytes backward to move. May be
912 TkTextIndex *dstPtr; /* Destination index: gets modified. */
914 TkTextSegment *segPtr;
918 TkTextIndexForwBytes(srcPtr, -byteCount, dstPtr);
923 dstPtr->byteIndex -= byteCount;
925 while (dstPtr->byteIndex < 0) {
927 * Move back one line in the text. If we run off the beginning
928 * of the file then just return the first character in the text.
932 lineIndex = TkBTreeLineIndex(dstPtr->linePtr);
934 if (lineIndex == 0) {
935 dstPtr->byteIndex = 0;
939 dstPtr->linePtr = TkBTreeFindLine(dstPtr->tree, lineIndex);
942 * Compute the length of the line and add that to dstPtr->charIndex.
945 for (segPtr = dstPtr->linePtr->segPtr; segPtr != NULL;
946 segPtr = segPtr->nextPtr) {
947 dstPtr->byteIndex += segPtr->size;
953 *---------------------------------------------------------------------------
955 * TkTextIndexBackChars --
957 * Given an index for a text widget, this procedure creates a new
958 * index that points "count" characters earlier than the source index.
961 * *dstPtr is modified to refer to the character "count" characters
962 * before srcPtr, or to the first character in the file if there
963 * aren't "count" characters earlier than srcPtr.
968 *---------------------------------------------------------------------------
972 TkTextIndexBackChars(srcPtr, charCount, dstPtr)
973 CONST TkTextIndex *srcPtr; /* Source index. */
974 int charCount; /* How many characters backward to move.
975 * May be negative. */
976 TkTextIndex *dstPtr; /* Destination index: gets modified. */
978 TkTextSegment *segPtr, *oldPtr;
979 int lineIndex, segSize;
980 char *p, *start, *end;
982 if (charCount <= 0) {
983 TkTextIndexForwChars(srcPtr, -charCount, dstPtr);
990 * Find offset within seg that contains byteIndex.
991 * Move backward specified number of chars.
996 segSize = dstPtr->byteIndex;
997 for (segPtr = dstPtr->linePtr->segPtr; ; segPtr = segPtr->nextPtr) {
998 if (segSize <= segPtr->size) {
1001 segSize -= segPtr->size;
1004 if (segPtr->typePtr == &tkTextCharType) {
1005 start = segPtr->body.chars;
1006 end = segPtr->body.chars + segSize;
1007 for (p = end; ; p = Tcl_UtfPrev(p, start)) {
1008 if (charCount == 0) {
1009 dstPtr->byteIndex -= (end - p);
1018 if (charCount <= segSize) {
1019 dstPtr->byteIndex -= charCount;
1022 charCount -= segSize;
1024 dstPtr->byteIndex -= segSize;
1027 * Move back into previous segment.
1031 segPtr = dstPtr->linePtr->segPtr;
1032 if (segPtr != oldPtr) {
1033 for ( ; segPtr->nextPtr != oldPtr; segPtr = segPtr->nextPtr) {
1036 segSize = segPtr->size;
1041 * Move back to previous line.
1044 if (lineIndex < 0) {
1045 lineIndex = TkBTreeLineIndex(dstPtr->linePtr);
1047 if (lineIndex == 0) {
1048 dstPtr->byteIndex = 0;
1052 dstPtr->linePtr = TkBTreeFindLine(dstPtr->tree, lineIndex);
1055 * Compute the length of the line and add that to dstPtr->byteIndex.
1058 oldPtr = dstPtr->linePtr->segPtr;
1059 for (segPtr = oldPtr; segPtr != NULL; segPtr = segPtr->nextPtr) {
1060 dstPtr->byteIndex += segPtr->size;
1064 segSize = segPtr->size;
1069 *----------------------------------------------------------------------
1073 * This procedure handles modifiers like "wordstart" and "lineend"
1074 * to adjust indices forwards or backwards.
1077 * If the modifier is successfully parsed then the return value
1078 * is the address of the first character after the modifier, and
1079 * *indexPtr is updated to reflect the modifier. If there is a
1080 * syntax error in the modifier then NULL is returned.
1085 *----------------------------------------------------------------------
1089 StartEnd(string, indexPtr)
1090 char *string; /* String to parse for additional info
1091 * about modifier (count and units).
1092 * Points to first character of modifer
1094 TkTextIndex *indexPtr; /* Index to mdoify based on string. */
1099 register TkTextSegment *segPtr;
1102 * Find the end of the modifier word.
1105 for (p = string; isalnum(UCHAR(*p)); p++) {
1106 /* Empty loop body. */
1109 if ((*string == 'l') && (strncmp(string, "lineend", length) == 0)
1111 indexPtr->byteIndex = 0;
1112 for (segPtr = indexPtr->linePtr->segPtr; segPtr != NULL;
1113 segPtr = segPtr->nextPtr) {
1114 indexPtr->byteIndex += segPtr->size;
1116 indexPtr->byteIndex -= sizeof(char);
1117 } else if ((*string == 'l') && (strncmp(string, "linestart", length) == 0)
1119 indexPtr->byteIndex = 0;
1120 } else if ((*string == 'w') && (strncmp(string, "wordend", length) == 0)
1125 * If the current character isn't part of a word then just move
1126 * forward one character. Otherwise move forward until finding
1127 * a character that isn't part of a word and stop there.
1130 segPtr = TkTextIndexToSeg(indexPtr, &offset);
1132 if (segPtr->typePtr == &tkTextCharType) {
1133 c = segPtr->body.chars[offset];
1134 if (!isalnum(UCHAR(c)) && (c != '_')) {
1140 indexPtr->byteIndex += sizeof(char);
1141 if (offset >= segPtr->size) {
1142 segPtr = TkTextIndexToSeg(indexPtr, &offset);
1146 TkTextIndexForwChars(indexPtr, 1, indexPtr);
1148 } else if ((*string == 'w') && (strncmp(string, "wordstart", length) == 0)
1153 * Starting with the current character, look for one that's not
1154 * part of a word and keep moving backward until you find one.
1155 * Then if the character found wasn't the first one, move forward
1156 * again one position.
1159 segPtr = TkTextIndexToSeg(indexPtr, &offset);
1161 if (segPtr->typePtr == &tkTextCharType) {
1162 c = segPtr->body.chars[offset];
1163 if (!isalnum(UCHAR(c)) && (c != '_')) {
1169 indexPtr->byteIndex -= sizeof(char);
1171 if (indexPtr->byteIndex < 0) {
1172 indexPtr->byteIndex = 0;
1175 segPtr = TkTextIndexToSeg(indexPtr, &offset);
1179 TkTextIndexForwChars(indexPtr, 1, indexPtr);