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

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tktextmark.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.69  
changed lines
  Added in v.220

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25