diff options
Diffstat (limited to 'generic/tkText.c')
-rw-r--r-- | generic/tkText.c | 5116 |
1 files changed, 2635 insertions, 2481 deletions
diff --git a/generic/tkText.c b/generic/tkText.c index f7dc176..bb4044b 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -1,20 +1,19 @@ -/* +/* * tkText.c -- * - * This module provides a big chunk of the implementation of - * multi-line editable text widgets for Tk. Among other things, it - * provides the Tcl command interfaces to text widgets. The B-tree - * representation of text and its actual display are implemented - * elsewhere. + * This module provides a big chunk of the implementation of multi-line + * editable text widgets for Tk. Among other things, it provides the Tcl + * command interfaces to text widgets. The B-tree representation of text + * and its actual display are implemented elsewhere. * * Copyright (c) 1992-1994 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkText.c,v 1.57 2005/04/04 22:00:05 vincentdarley Exp $ + * RCS: @(#) $Id: tkText.c,v 1.58 2005/08/10 22:02:22 dkf Exp $ */ #include "default.h" @@ -29,26 +28,27 @@ /* * For compatibility with Tk 4.0 through 8.4.x, we allow tabs to be - * mis-specified with non-increasing values. These are converted into - * tabs which are the equivalent of at least a character width apart. + * mis-specified with non-increasing values. These are converted into tabs + * which are the equivalent of at least a character width apart. */ + #if (TK_MAJOR_VERSION < 9) #define _TK_ALLOW_DECREASING_TABS #endif #include "tkText.h" -/* - * Used to avoid having to allocate and deallocate arrays on the - * fly for commonly used procedures. Must be > 0. +/* + * Used to avoid having to allocate and deallocate arrays on the fly for + * commonly used functions. Must be > 0. */ #define PIXEL_CLIENTS 5 /* - * The 'TkTextState' enum in tkText.h is used to define a type for the - * -state option of the Text widget. These values are used as indices - * into the string table below. + * The 'TkTextState' enum in tkText.h is used to define a type for the -state + * option of the Text widget. These values are used as indices into the string + * table below. */ static char *stateStrings[] = { @@ -56,9 +56,9 @@ static char *stateStrings[] = { }; /* - * The 'TkWrapMode' enum in tkText.h is used to define a type for the - * -wrap option of the Text widget. These values are used as indices - * into the string table below. + * The 'TkWrapMode' enum in tkText.h is used to define a type for the -wrap + * option of the Text widget. These values are used as indices into the string + * table below. */ static char *wrapStrings[] = { @@ -69,22 +69,24 @@ static char *wrapStrings[] = { * The following functions and custom option type are used to define the * "line" option type, and thereby handle the text widget '-startline', * '-endline' configuration options which are of that type. - * - * We do not need a 'freeProc' because all changes to these two options - * are handled through the TK_TEXT_LINE_RANGE flag in the optionSpecs - * list, and the internal storage is just a pointer, which therefore - * doesn't need freeing. + * + * We do not need a 'freeProc' because all changes to these two options are + * handled through the TK_TEXT_LINE_RANGE flag in the optionSpecs list, and + * the internal storage is just a pointer, which therefore doesn't need + * freeing. */ -static int SetLineStartEnd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, Tk_Window tkwin, - Tcl_Obj **value, char *recordPtr, int internalOffset, - char *oldInternalPtr, int flags)); -static Tcl_Obj* GetLineStartEnd _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, - char *recordPtr, int internalOffset)); -static void RestoreLineStartEnd _ANSI_ARGS_((ClientData clientData, - Tk_Window tkwin, char *internalPtr, - char *oldInternalPtr)); -static int ObjectIsEmpty _ANSI_ARGS_((Tcl_Obj *objPtr)); + +static int SetLineStartEnd(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + Tcl_Obj **value, char *recordPtr, + int internalOffset, char *oldInternalPtr, + int flags); +static Tcl_Obj* GetLineStartEnd(ClientData clientData, Tk_Window tkwin, + char *recordPtr, int internalOffset); +static void RestoreLineStartEnd(ClientData clientData, + Tk_Window tkwin, char *internalPtr, + char *oldInternalPtr); +static int ObjectIsEmpty(Tcl_Obj *objPtr); static Tk_ObjCustomOption lineOption = { "line", /* name */ @@ -101,21 +103,21 @@ static Tk_ObjCustomOption lineOption = { static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_BOOLEAN, "-autoseparators", "autoSeparators", - "AutoSeparators", DEF_TEXT_AUTO_SEPARATORS, -1, - Tk_Offset(TkText, autoSeparators), 0, 0, 0}, + "AutoSeparators", DEF_TEXT_AUTO_SEPARATORS, -1, + Tk_Offset(TkText, autoSeparators), 0, 0, 0}, {TK_OPTION_BORDER, "-background", "background", "Background", DEF_TEXT_BG_COLOR, -1, Tk_Offset(TkText, border), 0, (ClientData) DEF_TEXT_BG_MONO, 0}, {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, - (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", + (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", TK_TEXT_LINE_GEOMETRY}, {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, {TK_OPTION_BOOLEAN, "-blockcursor", "blockCursor", - "BlockCursor", DEF_TEXT_BLOCK_CURSOR, -1, + "BlockCursor", DEF_TEXT_BLOCK_CURSOR, -1, Tk_Offset(TkText, insertCursorType), 0, 0, 0}, {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_TEXT_BORDER_WIDTH, -1, Tk_Offset(TkText, borderWidth), + DEF_TEXT_BORDER_WIDTH, -1, Tk_Offset(TkText, borderWidth), 0, 0, TK_TEXT_LINE_GEOMETRY}, {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", DEF_TEXT_CURSOR, -1, Tk_Offset(TkText, cursor), @@ -124,70 +126,70 @@ static Tk_OptionSpec optionSpecs[] = { NULL, -1, Tk_Offset(TkText, end), TK_OPTION_NULL_OK, (ClientData) &lineOption, TK_TEXT_LINE_RANGE}, {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection", - "ExportSelection", DEF_TEXT_EXPORT_SELECTION, -1, + "ExportSelection", DEF_TEXT_EXPORT_SELECTION, -1, Tk_Offset(TkText, exportSelection), 0, 0, 0}, {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, {TK_OPTION_FONT, "-font", "font", "Font", - DEF_TEXT_FONT, -1, Tk_Offset(TkText, tkfont), 0, 0, + DEF_TEXT_FONT, -1, Tk_Offset(TkText, tkfont), 0, 0, TK_TEXT_LINE_GEOMETRY}, {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", - DEF_TEXT_FG, -1, Tk_Offset(TkText, fgColor), 0, + DEF_TEXT_FG, -1, Tk_Offset(TkText, fgColor), 0, 0, 0}, {TK_OPTION_PIXELS, "-height", "height", "Height", DEF_TEXT_HEIGHT, -1, Tk_Offset(TkText, height), 0, 0, 0}, {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_TEXT_HIGHLIGHT_BG, - -1, Tk_Offset(TkText, highlightBgColorPtr), + -1, Tk_Offset(TkText, highlightBgColorPtr), 0, 0, 0}, {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_TEXT_HIGHLIGHT, -1, Tk_Offset(TkText, highlightColorPtr), 0, 0, 0}, {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", - "HighlightThickness", DEF_TEXT_HIGHLIGHT_WIDTH, -1, + "HighlightThickness", DEF_TEXT_HIGHLIGHT_WIDTH, -1, Tk_Offset(TkText, highlightWidth), 0, 0, TK_TEXT_LINE_GEOMETRY}, - {TK_OPTION_BORDER, "-inactiveselectbackground", "inactiveSelectBackground", - "Foreground", + {TK_OPTION_BORDER, "-inactiveselectbackground", "inactiveSelectBackground", + "Foreground", #ifdef ALWAYS_SHOW_SELECTION - DEF_TEXT_SELECT_COLOR, + DEF_TEXT_SELECT_COLOR, #else - NULL, + NULL, #endif -1, Tk_Offset(TkText, inactiveSelBorder), TK_OPTION_NULL_OK, (ClientData) DEF_TEXT_SELECT_MONO, 0}, {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground", DEF_TEXT_INSERT_BG, - -1, Tk_Offset(TkText, insertBorder), + -1, Tk_Offset(TkText, insertBorder), 0, 0, 0}, - {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth", - "BorderWidth", DEF_TEXT_INSERT_BD_COLOR, -1, - Tk_Offset(TkText, insertBorderWidth), 0, + {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth", + "BorderWidth", DEF_TEXT_INSERT_BD_COLOR, -1, + Tk_Offset(TkText, insertBorderWidth), 0, (ClientData) DEF_TEXT_INSERT_BD_MONO, 0}, {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime", - DEF_TEXT_INSERT_OFF_TIME, -1, Tk_Offset(TkText, insertOffTime), + DEF_TEXT_INSERT_OFF_TIME, -1, Tk_Offset(TkText, insertOffTime), 0, 0, 0}, {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime", - DEF_TEXT_INSERT_ON_TIME, -1, Tk_Offset(TkText, insertOnTime), + DEF_TEXT_INSERT_ON_TIME, -1, Tk_Offset(TkText, insertOnTime), 0, 0, 0}, {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", - DEF_TEXT_INSERT_WIDTH, -1, Tk_Offset(TkText, insertWidth), + DEF_TEXT_INSERT_WIDTH, -1, Tk_Offset(TkText, insertWidth), 0, 0, 0}, {TK_OPTION_INT, "-maxundo", "maxUndo", "MaxUndo", DEF_TEXT_MAX_UNDO, -1, Tk_Offset(TkText, maxUndo), 0, 0, 0}, {TK_OPTION_PIXELS, "-padx", "padX", "Pad", - DEF_TEXT_PADX, -1, Tk_Offset(TkText, padX), 0, 0, + DEF_TEXT_PADX, -1, Tk_Offset(TkText, padX), 0, 0, TK_TEXT_LINE_GEOMETRY}, {TK_OPTION_PIXELS, "-pady", "padY", "Pad", DEF_TEXT_PADY, -1, Tk_Offset(TkText, padY), 0, 0, 0}, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", DEF_TEXT_RELIEF, -1, Tk_Offset(TkText, relief), 0, 0, 0}, {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground", - DEF_TEXT_SELECT_COLOR, -1, Tk_Offset(TkText, selBorder), + DEF_TEXT_SELECT_COLOR, -1, Tk_Offset(TkText, selBorder), 0, (ClientData) DEF_TEXT_SELECT_MONO, 0}, - {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", - "BorderWidth", DEF_TEXT_SELECT_BD_COLOR, - Tk_Offset(TkText, selBorderWidthPtr), - Tk_Offset(TkText, selBorderWidth), + {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", + "BorderWidth", DEF_TEXT_SELECT_BD_COLOR, + Tk_Offset(TkText, selBorderWidthPtr), + Tk_Offset(TkText, selBorderWidth), TK_OPTION_NULL_OK, (ClientData) DEF_TEXT_SELECT_BD_MONO, 0}, {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", DEF_TEXT_SELECT_FG_COLOR, -1, Tk_Offset(TkText, selFgColorPtr), @@ -207,234 +209,212 @@ static Tk_OptionSpec optionSpecs[] = { NULL, -1, Tk_Offset(TkText, start), TK_OPTION_NULL_OK, (ClientData) &lineOption, TK_TEXT_LINE_RANGE}, {TK_OPTION_STRING_TABLE, "-state", "state", "State", - DEF_TEXT_STATE, -1, Tk_Offset(TkText, state), + DEF_TEXT_STATE, -1, Tk_Offset(TkText, state), 0, (ClientData) stateStrings, 0}, {TK_OPTION_STRING, "-tabs", "tabs", "Tabs", DEF_TEXT_TABS, Tk_Offset(TkText, tabOptionPtr), -1, TK_OPTION_NULL_OK, 0, TK_TEXT_LINE_GEOMETRY}, {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_TEXT_TAKE_FOCUS, -1, Tk_Offset(TkText, takeFocus), + DEF_TEXT_TAKE_FOCUS, -1, Tk_Offset(TkText, takeFocus), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_BOOLEAN, "-undo", "undo", "Undo", - DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo), 0, 0 , 0}, + DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo), 0, 0 , 0}, {TK_OPTION_INT, "-width", "width", "Width", - DEF_TEXT_WIDTH, -1, Tk_Offset(TkText, width), 0, 0, + DEF_TEXT_WIDTH, -1, Tk_Offset(TkText, width), 0, 0, TK_TEXT_LINE_GEOMETRY}, {TK_OPTION_STRING_TABLE, "-wrap", "wrap", "Wrap", - DEF_TEXT_WRAP, -1, Tk_Offset(TkText, wrapMode), + DEF_TEXT_WRAP, -1, Tk_Offset(TkText, wrapMode), 0, (ClientData) wrapStrings, TK_TEXT_LINE_GEOMETRY}, {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", - DEF_TEXT_XSCROLL_COMMAND, -1, Tk_Offset(TkText, xScrollCmd), + DEF_TEXT_XSCROLL_COMMAND, -1, Tk_Offset(TkText, xScrollCmd), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", - DEF_TEXT_YSCROLL_COMMAND, -1, Tk_Offset(TkText, yScrollCmd), + DEF_TEXT_YSCROLL_COMMAND, -1, Tk_Offset(TkText, yScrollCmd), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_END} }; /* * These three typedefs, the structure and the SearchPerform, SearchCore - * functions below are used for line-based searches of the text widget, - * and, in particular, to handle multi-line matching even though the text - * widget is a single-line based data structure. They are completely - * abstracted away from the Text widget internals, however, so could - * easily be re-used with any line-based entity to provide multi-line - * matching. - * - * We have abstracted this code away from the text widget to try to - * keep Tk as modular as possible. + * functions below are used for line-based searches of the text widget, and, + * in particular, to handle multi-line matching even though the text widget is + * a single-line based data structure. They are completely abstracted away + * from the Text widget internals, however, so could easily be re-used with + * any line-based entity to provide multi-line matching. + * + * We have abstracted this code away from the text widget to try to keep Tk as + * modular as possible. */ struct SearchSpec; /* Forward declaration. */ -typedef ClientData SearchAddLineProc _ANSI_ARGS_((int lineNum, - struct SearchSpec *searchSpecPtr, - Tcl_Obj *theLine, int *lenPtr, - int *extraLinesPtr)); -typedef int SearchMatchProc _ANSI_ARGS_((int lineNum, - struct SearchSpec *searchSpecPtr, - ClientData clientData, Tcl_Obj *theLine, - int matchOffset, int matchLength)); -typedef int SearchLineIndexProc _ANSI_ARGS_((Tcl_Interp *interp, +typedef ClientData SearchAddLineProc(int lineNum, + struct SearchSpec *searchSpecPtr, + Tcl_Obj *theLine, int *lenPtr, + int *extraLinesPtr); +typedef int SearchMatchProc(int lineNum, + struct SearchSpec *searchSpecPtr, + ClientData clientData, Tcl_Obj *theLine, + int matchOffset, int matchLength); +typedef int SearchLineIndexProc(Tcl_Interp *interp, Tcl_Obj *objPtr, struct SearchSpec *searchSpecPtr, - int *linePosPtr, int *offsetPosPtr)); + int *linePosPtr, int *offsetPosPtr); typedef struct SearchSpec { - int exact; /* Whether search is exact or regexp */ - int noCase; /* Case-insenstivive? */ - int noLineStop; /* If not set, a regexp search will - * use the TCL_REG_NLSTOP flag */ - int overlap; /* If set, results from multiple - * searches (-all) are allowed to - * overlap each other. */ - int strictLimits; /* If set, matches must be - * completely inside the from,to - * range. Otherwise the limits - * only apply to the start of each - * match. */ - int all; /* Whether all or the first match should - * be reported */ - int startLine; /* First line to examine */ - int startOffset; /* Index in first line to start at */ - int stopLine; /* Last line to examine, or -1 when we - * search all available text */ - int stopOffset; /* Index to stop at, provided stopLine - * is not -1 */ - int numLines; /* Total lines which are available */ - int backwards; /* Searching forwards or backwards */ - Tcl_Obj *varPtr; /* If non-NULL, store length(s) of - * match(es) in this variable */ - Tcl_Obj *countPtr; /* Keeps track of currently found - * lengths */ - Tcl_Obj *resPtr; /* Keeps track of currently found - * locations */ - int searchElide; /* Search in hidden text as well */ - SearchAddLineProc *addLineProc; /* Function to call when we need to - * add another line to the search string - * so far */ - SearchMatchProc *foundMatchProc; /* Function to call when we have - * found a match */ - SearchLineIndexProc *lineIndexProc;/* Function to call when we have - * found a match */ - ClientData clientData; /* Information about structure being - * searched, in this case a text - * widget. */ + int exact; /* Whether search is exact or regexp */ + int noCase; /* Case-insenstivive? */ + int noLineStop; /* If not set, a regexp search will use the + * TCL_REG_NLSTOP flag. */ + int overlap; /* If set, results from multiple searches + * (-all) are allowed to overlap each + * other. */ + int strictLimits; /* If set, matches must be completely inside + * the from,to range. Otherwise the limits + * only apply to the start of each match. */ + int all; /* Whether all or the first match should be + * reported. */ + int startLine; /* First line to examine. */ + int startOffset; /* Index in first line to start at. */ + int stopLine; /* Last line to examine, or -1 when we search + * all available text. */ + int stopOffset; /* Index to stop at, provided stopLine is not + * -1 */ + int numLines; /* Total lines which are available. */ + int backwards; /* Searching forwards or backwards. */ + Tcl_Obj *varPtr; /* If non-NULL, store length(s) of match(es) + * in this variable. */ + Tcl_Obj *countPtr; /* Keeps track of currently found lengths. */ + Tcl_Obj *resPtr; /* Keeps track of currently found locations */ + int searchElide; /* Search in hidden text as well. */ + SearchAddLineProc *addLineProc; + /* Function to call when we need to add + * another line to the search string so far */ + SearchMatchProc *foundMatchProc; + /* Function to call when we have found a + * match. */ + SearchLineIndexProc *lineIndexProc; + /* Function to call when we have found a + * match. */ + ClientData clientData; /* Information about structure being searched, + * in this case a text widget. */ } SearchSpec; -/* - * The text-widget-independent functions which actually perform - * the search, handling both regexp and exact searches. +/* + * The text-widget-independent functions which actually perform the search, + * handling both regexp and exact searches. */ -static int SearchCore _ANSI_ARGS_((Tcl_Interp *interp, - SearchSpec *searchSpecPtr, Tcl_Obj *patObj)); -static int SearchPerform _ANSI_ARGS_((Tcl_Interp *interp, + +static int SearchCore(Tcl_Interp *interp, + SearchSpec *searchSpecPtr, Tcl_Obj *patObj); +static int SearchPerform(Tcl_Interp *interp, SearchSpec *searchSpecPtr, Tcl_Obj *patObj, - Tcl_Obj *fromPtr, Tcl_Obj *toPtr)); + Tcl_Obj *fromPtr, Tcl_Obj *toPtr); /* - * Boolean variable indicating whether or not special debugging code - * should be executed. + * Boolean variable indicating whether or not special debugging code should be + * executed. */ int tkTextDebug = 0; /* - * Forward declarations for procedures defined later in this file: + * Forward declarations for functions defined later in this file: */ -static int ConfigureText _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, int objc, Tcl_Obj *CONST objv[])); -static int DeleteChars _ANSI_ARGS_((TkSharedText *sharedPtr, - TkText *textPtr, - CONST TkTextIndex *indexPtr1, - CONST TkTextIndex *indexPtr2, int viewUpdate)); -static int CountIndices _ANSI_ARGS_((CONST TkText *textPtr, - CONST TkTextIndex *indexPtr1, - CONST TkTextIndex *indexPtr2, - TkTextCountType type)); -static void DestroyText _ANSI_ARGS_((TkText *textPtr)); -static int InsertChars _ANSI_ARGS_((TkSharedText *sharedTextPtr, - TkText *textPtr, - TkTextIndex *indexPtr, Tcl_Obj *stringPtr, - int viewUpdate)); -static void TextBlinkProc _ANSI_ARGS_((ClientData clientData)); -static void TextCmdDeletedProc _ANSI_ARGS_(( - ClientData clientData)); -static int CreateWidget _ANSI_ARGS_((TkSharedText *sharedPtr, - Tk_Window tkwin, Tcl_Interp *interp, - CONST TkText *parent, - int objc, Tcl_Obj *CONST objv[])); -static void TextEventProc _ANSI_ARGS_((ClientData clientData, - XEvent *eventPtr)); -static int TextFetchSelection _ANSI_ARGS_((ClientData clientData, - int offset, char *buffer, int maxBytes)); -static int TextIndexSortProc _ANSI_ARGS_((CONST VOID *first, - CONST VOID *second)); -static int TextInsertCmd _ANSI_ARGS_((TkSharedText *sharedTextPtr, - TkText *textPtr, - Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[], - CONST TkTextIndex *indexPtr, int viewUpdate)); -static int TextReplaceCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, +static int ConfigureText(Tcl_Interp *interp, + TkText *textPtr, int objc, Tcl_Obj *CONST objv[]); +static int DeleteChars(TkSharedText *sharedPtr, TkText *textPtr, + CONST TkTextIndex *indexPtr1, + CONST TkTextIndex *indexPtr2, int viewUpdate); +static int CountIndices(CONST TkText *textPtr, + CONST TkTextIndex *indexPtr1, + CONST TkTextIndex *indexPtr2, + TkTextCountType type); +static void DestroyText(TkText *textPtr); +static int InsertChars(TkSharedText *sharedTextPtr, + TkText *textPtr, TkTextIndex *indexPtr, + Tcl_Obj *stringPtr, int viewUpdate); +static void TextBlinkProc(ClientData clientData); +static void TextCmdDeletedProc(ClientData clientData); +static int CreateWidget(TkSharedText *sharedPtr, Tk_Window tkwin, + Tcl_Interp *interp, CONST TkText *parent, + int objc, Tcl_Obj *CONST objv[]); +static void TextEventProc(ClientData clientData, XEvent *eventPtr); +static int TextFetchSelection(ClientData clientData, int offset, + char *buffer, int maxBytes); +static int TextIndexSortProc(CONST VOID *first, + CONST VOID *second); +static int TextInsertCmd(TkSharedText *sharedTextPtr, + TkText *textPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[], + CONST TkTextIndex *indexPtr, int viewUpdate); +static int TextReplaceCmd(TkText *textPtr, Tcl_Interp *interp, CONST TkTextIndex *indexFromPtr, CONST TkTextIndex *indexToPtr, - int objc, Tcl_Obj *CONST objv[], - int viewUpdate)); -static int TextSearchCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[])); -static int TextEditCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[])); -static int TextWidgetObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[])); -static int SharedTextObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[])); -static void TextWorldChangedCallback _ANSI_ARGS_(( - ClientData instanceData)); -static void TextWorldChanged _ANSI_ARGS_((TkText *textPtr, - int mask)); -static int TextDumpCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[])); -static void DumpLine _ANSI_ARGS_((Tcl_Interp *interp, - TkText *textPtr, int what, TkTextLine *linePtr, - int start, int end, int lineno, - CONST char *command)); -static int DumpSegment _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, - CONST char *key, - CONST char *value, CONST char * command, - CONST TkTextIndex *index, int what)); -static int TextEditUndo _ANSI_ARGS_((TkText *textPtr)); -static int TextEditRedo _ANSI_ARGS_((TkText *textPtr)); -static Tcl_Obj* TextGetText _ANSI_ARGS_((CONST TkText *textPtr, - CONST TkTextIndex * index1, - CONST TkTextIndex * index2, int visibleOnly)); -static void UpdateDirtyFlag _ANSI_ARGS_((TkSharedText *sharedPtr)); -static void TextPushUndoAction _ANSI_ARGS_((TkText *textPtr, - Tcl_Obj *undoString, int insert, + int objc, Tcl_Obj *CONST objv[], int viewUpdate); +static int TextSearchCmd(TkText *textPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +static int TextEditCmd(TkText *textPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +static int TextWidgetObjCmd(ClientData clientData, + Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +static int SharedTextObjCmd(ClientData clientData, + Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +static void TextWorldChangedCallback(ClientData instanceData); +static void TextWorldChanged(TkText *textPtr, int mask); +static int TextDumpCmd(TkText *textPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +static void DumpLine(Tcl_Interp *interp, TkText *textPtr, int what, + TkTextLine *linePtr, int start, int end, + int lineno, CONST char *command); +static int DumpSegment(TkText *textPtr, Tcl_Interp *interp, + CONST char *key, CONST char *value, + CONST char *command, CONST TkTextIndex *index, + int what); +static int TextEditUndo(TkText *textPtr); +static int TextEditRedo(TkText *textPtr); +static Tcl_Obj * TextGetText(CONST TkText *textPtr, + CONST TkTextIndex *index1, + CONST TkTextIndex *index2, int visibleOnly); +static void UpdateDirtyFlag(TkSharedText *sharedPtr); +static void TextPushUndoAction(TkText *textPtr, + Tcl_Obj *undoString, int insert, CONST TkTextIndex *index1Ptr, - CONST TkTextIndex *index2Ptr)); -static int TextSearchIndexInLine _ANSI_ARGS_(( - CONST SearchSpec *searchSpecPtr, - TkTextLine *linePtr, int byteIndex)); -static int TextPeerCmd _ANSI_ARGS_((TkText *textPtr, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[])); -static TkUndoProc TextUndoRedoCallback; - -/* - * Declarations of the three search procs required by - * the multi-line search routines + CONST TkTextIndex *index2Ptr); +static int TextSearchIndexInLine(CONST SearchSpec *searchSpecPtr, + TkTextLine *linePtr, int byteIndex); +static int TextPeerCmd(TkText *textPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); +static TkUndoProc TextUndoRedoCallback; + +/* + * Declarations of the three search procs required by the multi-line search + * routines. */ -static SearchMatchProc TextSearchFoundMatch; -static SearchAddLineProc TextSearchAddNextLine; -static SearchLineIndexProc TextSearchGetLineIndex; - +static SearchMatchProc TextSearchFoundMatch; +static SearchAddLineProc TextSearchAddNextLine; +static SearchLineIndexProc TextSearchGetLineIndex; /* - * The structure below defines text class behavior by means of procedures - * that can be invoked from generic window code. + * The structure below defines text class behavior by means of functions that + * can be invoked from generic window code. */ static Tk_ClassProcs textClass = { sizeof(Tk_ClassProcs), /* size */ TextWorldChangedCallback, /* worldChangedProc */ }; - /* *-------------------------------------------------------------- * * Tk_TextObjCmd -- * - * This procedure is invoked to process the "text" Tcl command. - * See the user documentation for details on what it does. + * This function is invoked to process the "text" Tcl command. See the + * user documentation for details on what it does. * * Results: * A standard Tcl result. @@ -447,8 +427,7 @@ static Tk_ClassProcs textClass = { int Tk_TextObjCmd(clientData, interp, objc, objv) - ClientData clientData; /* Main window associated with - * interpreter. */ + ClientData clientData; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ @@ -468,15 +447,15 @@ Tk_TextObjCmd(clientData, interp, objc, objv) * * CreateWidget -- * - * This procedure is invoked to process the "text" Tcl command, - * (when called by Tk_TextObjCmd) and the "$text peer create" - * text widget sub-command (called from TextPeerCmd). - * + * This function is invoked to process the "text" Tcl command, (when + * called by Tk_TextObjCmd) and the "$text peer create" text widget + * sub-command (called from TextPeerCmd). + * * See the user documentation for details on what it does. * * Results: - * A standard Tcl result, places the name of the widget - * created into the interp's result. + * A standard Tcl result, places the name of the widget created into the + * interp's result. * * Side effects: * See the user documentation. @@ -487,11 +466,10 @@ Tk_TextObjCmd(clientData, interp, objc, objv) static int CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) TkSharedText *sharedPtr; /* Shared widget info, or null */ - Tk_Window tkwin; /* Main window associated with - * interpreter. */ + Tk_Window tkwin; /* Main window associated with interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ - CONST TkText *parent; /* If non-NULL then take default - * start, end from this parent. */ + CONST TkText *parent; /* If non-NULL then take default start, end + * from this parent. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { @@ -499,22 +477,21 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) Tk_OptionTable optionTable; TkTextIndex startIndex; Tk_Window new; - + /* * Create the window. */ - new = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]), - (char *) NULL); + new = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(objv[1]), + (char *) NULL); if (new == NULL) { return TCL_ERROR; } /* - * Create the text widget and initialize everything to zero, - * then set the necessary initial (non-NULL) values. It is - * important that the 'set' tag and 'insert', 'current' mark - * pointers are all NULL to start. + * Create the text widget and initialize everything to zero, then set the + * necessary initial (non-NULL) values. It is important that the 'set' tag + * and 'insert', 'current' mark pointers are all NULL to start. */ textPtr = (TkText *) ckalloc(sizeof(TkText)); @@ -530,11 +507,11 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) if (sharedPtr == NULL) { sharedPtr = (TkSharedText *) ckalloc(sizeof(TkSharedText)); memset((VOID *) sharedPtr, 0, sizeof(TkSharedText)); - + sharedPtr->refCount = 0; sharedPtr->peers = NULL; sharedPtr->tree = TkBTreeCreate(sharedPtr); - + Tcl_InitHashTable(&sharedPtr->tagTable, TCL_STRING_KEYS); Tcl_InitHashTable(&sharedPtr->markTable, TCL_STRING_KEYS); Tcl_InitHashTable(&sharedPtr->windowTable, TCL_STRING_KEYS); @@ -547,24 +524,28 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) sharedPtr->stateEpoch = 0; } - /* Add the new widget to the shared list */ + /* + * Add the new widget to the shared list. + */ + textPtr->sharedTextPtr = sharedPtr; sharedPtr->refCount++; textPtr->next = sharedPtr->peers; sharedPtr->peers = textPtr; - /* - * This refCount will be held until DestroyText is called. - * Note also that the later call to 'TkTextCreateDInfo' - * will add more refCounts. + + /* + * This refCount will be held until DestroyText is called. Note also that + * the later call to 'TkTextCreateDInfo' will add more refCounts. */ + textPtr->refCount = 1; - /* - * Specify start and end lines in the B-tree. The default - * is the same as the parent, but this can be adjusted to - * display more or less if the start, end where given - * as configuration options. + /* + * Specify start and end lines in the B-tree. The default is the same as + * the parent, but this can be adjusted to display more or less if the + * start, end where given as configuration options. */ + if (parent != NULL) { textPtr->start = parent->start; textPtr->end = parent->end; @@ -573,12 +554,12 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) textPtr->end = NULL; } - /* - * Register with the B-tree. In some sense it would be best - * if we could do this later (after configuration options), - * so that any changes to start,end do not require a total - * recalculation. + /* + * Register with the B-tree. In some sense it would be best if we could do + * this later (after configuration options), so that any changes to + * start,end do not require a total recalculation. */ + TkBTreeAddClient(sharedPtr->tree, textPtr, textPtr->charHeight); textPtr->state = TK_TEXT_STATE_NORMAL; @@ -589,10 +570,14 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) textPtr->wrapMode = TEXT_WRAPMODE_CHAR; textPtr->prevWidth = Tk_Width(new); textPtr->prevHeight = Tk_Height(new); - /* This will add refCounts to textPtr */ + + /* + * This will add refCounts to textPtr. + */ + TkTextCreateDInfo(textPtr); - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - 0, 0, &startIndex); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0, + &startIndex); TkTextSetYView(textPtr, &startIndex, 0); textPtr->exportSelection = 1; textPtr->pickEvent.type = LeaveNotify; @@ -600,7 +585,7 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) textPtr->maxUndo = textPtr->sharedTextPtr->maxUndo; textPtr->autoSeparators = textPtr->sharedTextPtr->autoSeparators; textPtr->tabOptionPtr = NULL; - + /* * Create the "sel" tag and the "current" and "insert" marks. */ @@ -610,21 +595,23 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) textPtr->selBorderWidth = 0; textPtr->selBorderWidthPtr = NULL; textPtr->selFgColorPtr = NULL; - /* - * Note: it is important that textPtr->selTagPtr is NULL before - * this initial call. + + /* + * Note: it is important that textPtr->selTagPtr is NULL before this + * initial call. */ + textPtr->selTagPtr = TkTextCreateTag(textPtr, "sel", NULL); - textPtr->selTagPtr->reliefString = - (char *) ckalloc(sizeof(DEF_TEXT_SELECT_RELIEF)); + textPtr->selTagPtr->reliefString = (char *) + ckalloc(sizeof(DEF_TEXT_SELECT_RELIEF)); strcpy(textPtr->selTagPtr->reliefString, DEF_TEXT_SELECT_RELIEF); textPtr->selTagPtr->relief = TK_RELIEF_RAISED; textPtr->currentMarkPtr = TkTextSetMark(textPtr, "current", &startIndex); textPtr->insertMarkPtr = TkTextSetMark(textPtr, "insert", &startIndex); /* - * Create the option table for this widget class. If it has already - * been created, the cached pointer will be returned. + * Create the option table for this widget class. If it has already been + * created, the cached pointer will be returned. */ optionTable = Tk_CreateOptionTable(interp, optionSpecs); @@ -642,7 +629,7 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) TkTextBindProc, (ClientData) textPtr); Tk_CreateSelHandler(textPtr->tkwin, XA_PRIMARY, XA_STRING, TextFetchSelection, (ClientData) textPtr, XA_STRING); - + if (Tk_InitOptions(interp, (char *) textPtr, optionTable, textPtr->tkwin) != TCL_OK) { Tk_DestroyWindow(textPtr->tkwin); @@ -653,8 +640,8 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) return TCL_ERROR; } - Tcl_SetObjResult(interp, - Tcl_NewStringObj(Tk_PathName(textPtr->tkwin),-1)); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(Tk_PathName(textPtr->tkwin),-1)); return TCL_OK; } @@ -663,9 +650,9 @@ CreateWidget(sharedPtr, tkwin, interp, parent, objc, objv) * * TextWidgetObjCmd -- * - * This procedure is invoked to process the Tcl command - * that corresponds to a text widget. See the user - * documentation for details on what it does. + * This function is invoked to process the Tcl command that corresponds + * to a text widget. See the user documentation for details on what it + * does. * * Results: * A standard Tcl result. @@ -686,21 +673,21 @@ TextWidgetObjCmd(clientData, interp, objc, objv) register TkText *textPtr = (TkText *) clientData; int result = TCL_OK; int index; - + static CONST char *optionStrings[] = { - "bbox", "cget", "compare", "configure", "count", "debug", - "delete", "dlineinfo", "dump", "edit", "get", "image", "index", - "insert", "mark", "peer", "replace", "scan", "search", "see", - "tag", "window", "xview", "yview", (char *) NULL + "bbox", "cget", "compare", "configure", "count", "debug", + "delete", "dlineinfo", "dump", "edit", "get", "image", "index", + "insert", "mark", "peer", "replace", "scan", "search", "see", + "tag", "window", "xview", "yview", (char *) NULL }; enum options { - TEXT_BBOX, TEXT_CGET, TEXT_COMPARE, TEXT_CONFIGURE, TEXT_COUNT, - TEXT_DEBUG, TEXT_DELETE, TEXT_DLINEINFO, TEXT_DUMP, TEXT_EDIT, - TEXT_GET, TEXT_IMAGE, TEXT_INDEX, TEXT_INSERT, TEXT_MARK, - TEXT_PEER, TEXT_REPLACE, TEXT_SCAN, TEXT_SEARCH, TEXT_SEE, + TEXT_BBOX, TEXT_CGET, TEXT_COMPARE, TEXT_CONFIGURE, TEXT_COUNT, + TEXT_DEBUG, TEXT_DELETE, TEXT_DLINEINFO, TEXT_DUMP, TEXT_EDIT, + TEXT_GET, TEXT_IMAGE, TEXT_INDEX, TEXT_INSERT, TEXT_MARK, + TEXT_PEER, TEXT_REPLACE, TEXT_SCAN, TEXT_SEARCH, TEXT_SEE, TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, TEXT_YVIEW }; - + if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; @@ -713,783 +700,784 @@ TextWidgetObjCmd(clientData, interp, objc, objv) textPtr->refCount++; switch ((enum options) index) { - case TEXT_BBOX: { - int x, y, width, height; - CONST TkTextIndex *indexPtr; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "index"); - result = TCL_ERROR; - goto done; - } - indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); - if (indexPtr == NULL) { - result = TCL_ERROR; - goto done; - } - if (TkTextCharBbox(textPtr, indexPtr, &x, &y, - &width, &height, NULL) == 0) { - Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); - - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(x)); - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(y)); - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(width)); - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(height)); - - Tcl_SetObjResult(interp, listObj); - } - break; + case TEXT_BBOX: { + int x, y, width, height; + CONST TkTextIndex *indexPtr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + result = TCL_ERROR; + goto done; + } + indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); + if (indexPtr == NULL) { + result = TCL_ERROR; + goto done; + } + if (TkTextCharBbox(textPtr, indexPtr, &x, &y, &width, &height, + NULL) == 0) { + Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); + + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(x)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(y)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(width)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(height)); + + Tcl_SetObjResult(interp, listObj); } - case TEXT_CGET: { - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "option"); + break; + } + case TEXT_CGET: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); + result = TCL_ERROR; + goto done; + } else { + Tcl_Obj *objPtr = Tk_GetOptionValue(interp, (char *) textPtr, + textPtr->optionTable, objv[2], textPtr->tkwin); + if (objPtr == NULL) { result = TCL_ERROR; goto done; } else { - Tcl_Obj *objPtr = Tk_GetOptionValue(interp, (char *) textPtr, - textPtr->optionTable, objv[2], textPtr->tkwin); - if (objPtr == NULL) { - result = TCL_ERROR; - goto done; - } else { - Tcl_SetObjResult(interp, objPtr); - result = TCL_OK; - } + Tcl_SetObjResult(interp, objPtr); + result = TCL_OK; } - break; } - case TEXT_COMPARE: { - int relation, value; - CONST char *p; - CONST TkTextIndex *index1Ptr, *index2Ptr; - - if (objc != 5) { - Tcl_WrongNumArgs(interp, 2, objv, "index1 op index2"); - result = TCL_ERROR; - goto done; - } - index1Ptr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); - index2Ptr = TkTextGetIndexFromObj(interp, textPtr, objv[4]); - if (index1Ptr == NULL || index2Ptr == NULL) { + break; + case TEXT_COMPARE: { + int relation, value; + CONST char *p; + CONST TkTextIndex *index1Ptr, *index2Ptr; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "index1 op index2"); + result = TCL_ERROR; + goto done; + } + index1Ptr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); + index2Ptr = TkTextGetIndexFromObj(interp, textPtr, objv[4]); + if (index1Ptr == NULL || index2Ptr == NULL) { + result = TCL_ERROR; + goto done; + } + relation = TkTextIndexCmp(index1Ptr, index2Ptr); + p = Tcl_GetString(objv[3]); + if (p[0] == '<') { + value = (relation < 0); + if ((p[1] == '=') && (p[2] == 0)) { + value = (relation <= 0); + } else if (p[1] != 0) { + compareError: + Tcl_AppendResult(interp, "bad comparison operator \"", + Tcl_GetString(objv[3]), + "\": must be <, <=, ==, >=, >, or !=", + (char *) NULL); result = TCL_ERROR; goto done; } - relation = TkTextIndexCmp(index1Ptr, index2Ptr); - p = Tcl_GetString(objv[3]); - if (p[0] == '<') { - value = (relation < 0); - if ((p[1] == '=') && (p[2] == 0)) { - value = (relation <= 0); - } else if (p[1] != 0) { - compareError: - Tcl_AppendResult(interp, "bad comparison operator \"", - Tcl_GetString(objv[3]), - "\": must be <, <=, ==, >=, >, or !=", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - } else if (p[0] == '>') { - value = (relation > 0); - if ((p[1] == '=') && (p[2] == 0)) { - value = (relation >= 0); - } else if (p[1] != 0) { - goto compareError; - } - } else if ((p[0] == '=') && (p[1] == '=') && (p[2] == 0)) { - value = (relation == 0); - } else if ((p[0] == '!') && (p[1] == '=') && (p[2] == 0)) { - value = (relation != 0); - } else { + } else if (p[0] == '>') { + value = (relation > 0); + if ((p[1] == '=') && (p[2] == 0)) { + value = (relation >= 0); + } else if (p[1] != 0) { goto compareError; } - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); - break; - } - case TEXT_CONFIGURE: { - if (objc <= 3) { - Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char *) textPtr, - textPtr->optionTable, - (objc == 3) ? objv[2] : (Tcl_Obj *) NULL, - textPtr->tkwin); - if (objPtr == NULL) { - result = TCL_ERROR; - goto done; - } else { - Tcl_SetObjResult(interp, objPtr); - } - } else { - result = ConfigureText(interp, textPtr, objc-2, objv+2); - } - break; + } else if ((p[0] == '=') && (p[1] == '=') && (p[2] == 0)) { + value = (relation == 0); + } else if ((p[0] == '!') && (p[1] == '=') && (p[2] == 0)) { + value = (relation != 0); + } else { + goto compareError; } - case TEXT_COUNT: { - CONST TkTextIndex *indexFromPtr, *indexToPtr; - int i, found = 0, update = 0; - Tcl_Obj *objPtr = NULL; - - if (objc < 4) { - Tcl_WrongNumArgs(interp, 2, objv, "?options? index1 index2"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); + break; + } + case TEXT_CONFIGURE: + if (objc <= 3) { + Tcl_Obj *objPtr = Tk_GetOptionInfo(interp, (char *) textPtr, + textPtr->optionTable, + ((objc == 3) ? objv[2] : (Tcl_Obj *) NULL), + textPtr->tkwin); + if (objPtr == NULL) { result = TCL_ERROR; goto done; + } else { + Tcl_SetObjResult(interp, objPtr); } + } else { + result = ConfigureText(interp, textPtr, objc-2, objv+2); + } + break; + case TEXT_COUNT: { + CONST TkTextIndex *indexFromPtr, *indexToPtr; + int i, found = 0, update = 0; + Tcl_Obj *objPtr = NULL; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, "?options? index1 index2"); + result = TCL_ERROR; + goto done; + } - indexFromPtr = TkTextGetIndexFromObj(interp, textPtr, objv[objc-2]); - if (indexFromPtr == NULL) { - result = TCL_ERROR; - goto done; - } - indexToPtr = TkTextGetIndexFromObj(interp, textPtr, objv[objc-1]); - if (indexToPtr == NULL) { - result = TCL_ERROR; - goto done; - } + indexFromPtr = TkTextGetIndexFromObj(interp, textPtr, objv[objc-2]); + if (indexFromPtr == NULL) { + result = TCL_ERROR; + goto done; + } + indexToPtr = TkTextGetIndexFromObj(interp, textPtr, objv[objc-1]); + if (indexToPtr == NULL) { + result = TCL_ERROR; + goto done; + } - for (i = 2; i < objc-2; i++) { - int value; - unsigned length; - CONST char *option = Tcl_GetStringFromObj(objv[i], - (int *)&length); - char c; - if (length < 2 || option[0] != '-') { - badOption: - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad option \"", - Tcl_GetString(objv[i]), + for (i = 2; i < objc-2; i++) { + int value, length; + CONST char *option = Tcl_GetStringFromObj(objv[i], &length); + char c; + + if (length < 2 || option[0] != '-') { + badOption: + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "bad option \"", + Tcl_GetString(objv[i]), "\" must be -chars, -displaychars, -displayindices, ", "-displaylines, -indices, -lines, -update, ", "-xpixels, or -ypixels", NULL); - result = TCL_ERROR; - goto done; + result = TCL_ERROR; + goto done; + } + c = option[1]; + if (c == 'c' && !strncmp("-chars", option, (unsigned) length)) { + value = CountIndices(textPtr, indexFromPtr, indexToPtr, + COUNT_CHARS); + } else if (c == 'd' && (length > 8) + && !strncmp("-displaychars", option, (unsigned) length)) { + value = CountIndices(textPtr, indexFromPtr, indexToPtr, + COUNT_DISPLAY_CHARS); + } else if (c == 'd' && (length > 8) + && !strncmp("-displayindices", option, (unsigned)length)) { + value = CountIndices(textPtr, indexFromPtr, indexToPtr, + COUNT_DISPLAY_INDICES); + } else if (c == 'd' && (length > 8) + && !strncmp("-displaylines", option, (unsigned) length)) { + TkTextLine *fromPtr, *lastPtr; + TkTextIndex index; + + int compare = TkTextIndexCmp(indexFromPtr, indexToPtr); + value = 0; + + if (compare == 0) { + goto countDone; } - c = option[1]; - if (c == 'c' && !strncmp("-chars",option,length)) { - value = CountIndices(textPtr, indexFromPtr, indexToPtr, - COUNT_CHARS); - } else if (c == 'd' && !strncmp("-displaychars", option, - length) && (length > 8)) { - value = CountIndices(textPtr, indexFromPtr, indexToPtr, - COUNT_DISPLAY_CHARS); - } else if (c == 'd' && !strncmp("-displayindices", option, - length) && (length > 8)) { - value = CountIndices(textPtr, indexFromPtr, indexToPtr, - COUNT_DISPLAY_INDICES); - } else if (c == 'd' && !strncmp("-displaylines", option, - length) && (length > 8)) { - TkTextLine *fromPtr, *lastPtr; - TkTextIndex index; - - int compare = TkTextIndexCmp(indexFromPtr, indexToPtr); - value = 0; - - if (compare == 0) goto countDone; - - if (compare > 0) { - CONST TkTextIndex *tmpPtr = indexFromPtr; - indexFromPtr = indexToPtr; - indexToPtr = tmpPtr; - } - lastPtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, - textPtr, - TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr)); - fromPtr = indexFromPtr->linePtr; - if (fromPtr == lastPtr) { - goto countDone; - } + if (compare > 0) { + CONST TkTextIndex *tmpPtr = indexFromPtr; + + indexFromPtr = indexToPtr; + indexToPtr = tmpPtr; + } + + lastPtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, + textPtr, + TkBTreeNumLines(textPtr->sharedTextPtr->tree,textPtr)); + fromPtr = indexFromPtr->linePtr; + if (fromPtr == lastPtr) { + goto countDone; + } + + /* + * Caution: we must NEVER call TkTextUpdateOneLine with the + * last artificial line in the widget. + */ - /* - * Caution: we must NEVER call TkTextUpdateOneLine - * with the last artificial line in the widget. + index = *indexFromPtr; + while (index.linePtr != indexToPtr->linePtr) { + value += TkTextUpdateOneLine(textPtr, fromPtr, 0,&index,0); + + /* + * We might have skipped past indexToPtr, if we have + * multiple logical lines in a single display line. + * Therefore we iterate through each intermediate logical + * line, just to check. Another approach would be just to + * use TkTextIndexCmp on every while() iteration, but that + * would be less efficient. */ - index = *indexFromPtr; - while (index.linePtr != indexToPtr->linePtr) { - value += TkTextUpdateOneLine(textPtr, fromPtr, - 0, &index, 0); - /* - * We might have skipped past indexToPtr, if we - * have multiple logical lines in a single - * display line. Therefore we iterate through - * each intermediate logical line, just to - * check. Another approach would be just to use - * TkTextIndexCmp on every while() iteration, - * but that would be less efficient. - */ - while (fromPtr != index.linePtr) { - fromPtr = TkBTreeNextLine(textPtr, fromPtr); - if (fromPtr == indexToPtr->linePtr) { - break; - } + + while (fromPtr != index.linePtr) { + fromPtr = TkBTreeNextLine(textPtr, fromPtr); + if (fromPtr == indexToPtr->linePtr) { + break; } } - /* - * Now we need to adjust the count to add on the - * number of display lines in the last logical line, - * and subtract off the number of display lines - * overcounted in the first logical line. This logic - * is still ok if both indices are in the same - * logical line. - */ - index.linePtr = indexFromPtr->linePtr; + } + + /* + * Now we need to adjust the count to add on the number of + * display lines in the last logical line, and subtract off + * the number of display lines overcounted in the first + * logical line. This logic is still ok if both indices are in + * the same logical line. + */ + + index.linePtr = indexFromPtr->linePtr; + index.byteIndex = 0; + while (1) { + TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL); + if (index.byteIndex >= indexFromPtr->byteIndex) { + break; + } + TkTextIndexForwBytes(textPtr, &index, 1, &index); + value--; + + } + if (indexToPtr->linePtr != lastPtr) { + index.linePtr = indexToPtr->linePtr; index.byteIndex = 0; while (1) { TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL); - if (index.byteIndex >= indexFromPtr->byteIndex) { + if (index.byteIndex >= indexToPtr->byteIndex) { break; } TkTextIndexForwBytes(textPtr, &index, 1, &index); - value--; + value++; } - if (indexToPtr->linePtr != lastPtr) { - index.linePtr = indexToPtr->linePtr; - index.byteIndex = 0; - while (1) { - TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL); - if (index.byteIndex >= indexToPtr->byteIndex) { - break; - } - TkTextIndexForwBytes(textPtr, &index, 1, &index); - value++; - } - } - - if (compare > 0) { - value = -value; - } - } else if (c == 'i' && !strncmp("-indices",option,length)) { - value = CountIndices(textPtr, indexFromPtr, indexToPtr, - COUNT_INDICES); - } else if (c == 'l' && !strncmp("-lines",option,length)) { - value = TkBTreeLinesTo(textPtr, indexToPtr->linePtr) - - TkBTreeLinesTo(textPtr, indexFromPtr->linePtr); - } else if (c == 'u' && !strncmp("-update",option,length)) { - update = 1; - continue; - } else if (c == 'x' && !strncmp("-xpixels",option,length)) { - int x1, x2; - TkTextIndex index; - index = *indexFromPtr; - TkTextFindDisplayLineEnd(textPtr, &index, 0, &x1); - index = *indexToPtr; - TkTextFindDisplayLineEnd(textPtr, &index, 0, &x2); - value = x2 - x1; - } else if (c == 'y' && !strncmp("-ypixels",option,length)) { - if (update) { - TkTextUpdateLineMetrics(textPtr, - TkBTreeLinesTo(textPtr, indexFromPtr->linePtr), - TkBTreeLinesTo(textPtr, indexToPtr->linePtr), -1); - } - value = TkTextIndexYPixels(textPtr, indexToPtr) - - TkTextIndexYPixels(textPtr, indexFromPtr); - } else { - goto badOption; } - countDone: - found++; - if (found == 1) { - Tcl_SetObjResult(interp, Tcl_NewIntObj(value)); - } else { - if (found == 2) { - /* - * Move the first item we put into the result into - * the first element of the list object. - */ - objPtr = Tcl_NewObj(); - Tcl_ListObjAppendElement(NULL, objPtr, - Tcl_GetObjResult(interp)); - } - Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewIntObj(value)); + + if (compare > 0) { + value = -value; + } + } else if (c == 'i' + && !strncmp("-indices", option, (unsigned) length)) { + value = CountIndices(textPtr, indexFromPtr, indexToPtr, + COUNT_INDICES); + } else if (c == 'l' + && !strncmp("-lines", option, (unsigned) length)) { + value = TkBTreeLinesTo(textPtr, indexToPtr->linePtr) + - TkBTreeLinesTo(textPtr, indexFromPtr->linePtr); + } else if (c == 'u' + && !strncmp("-update", option, (unsigned) length)) { + update = 1; + continue; + } else if (c == 'x' + && !strncmp("-xpixels", option, (unsigned) length)) { + int x1, x2; + TkTextIndex index; + + index = *indexFromPtr; + TkTextFindDisplayLineEnd(textPtr, &index, 0, &x1); + index = *indexToPtr; + TkTextFindDisplayLineEnd(textPtr, &index, 0, &x2); + value = x2 - x1; + } else if (c == 'y' + && !strncmp("-ypixels", option, (unsigned) length)) { + if (update) { + TkTextUpdateLineMetrics(textPtr, + TkBTreeLinesTo(textPtr, indexFromPtr->linePtr), + TkBTreeLinesTo(textPtr, indexToPtr->linePtr), -1); } + value = TkTextIndexYPixels(textPtr, indexToPtr) + - TkTextIndexYPixels(textPtr, indexFromPtr); + } else { + goto badOption; } - if (found == 0) { - /* Use the default '-indices' */ - int value = CountIndices(textPtr, indexFromPtr, indexToPtr, - COUNT_INDICES); + + countDone: + found++; + if (found == 1) { Tcl_SetObjResult(interp, Tcl_NewIntObj(value)); - } else if (found > 1) { - Tcl_SetObjResult(interp, objPtr); - } - break; - } - case TEXT_DEBUG: { - if (objc > 3) { - Tcl_WrongNumArgs(interp, 2, objv, "boolean"); - result = TCL_ERROR; - goto done; - } - if (objc == 2) { - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(tkBTreeDebug)); } else { - if (Tcl_GetBooleanFromObj(interp, objv[2], - &tkBTreeDebug) != TCL_OK) { - result = TCL_ERROR; - goto done; + if (found == 2) { + /* + * Move the first item we put into the result into + * the first element of the list object. + */ + objPtr = Tcl_NewObj(); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_GetObjResult(interp)); } - tkTextDebug = tkBTreeDebug; + Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewIntObj(value)); } - break; } - case TEXT_DELETE: { - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "index1 ?index2 ...?"); + + if (found == 0) { + /* + * Use the default '-indices'. + */ + + int value = CountIndices(textPtr, indexFromPtr, indexToPtr, + COUNT_INDICES); + Tcl_SetObjResult(interp, Tcl_NewIntObj(value)); + } else if (found > 1) { + Tcl_SetObjResult(interp, objPtr); + } + break; + } + case TEXT_DEBUG: + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "boolean"); + result = TCL_ERROR; + goto done; + } + if (objc == 2) { + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(tkBTreeDebug)); + } else { + if (Tcl_GetBooleanFromObj(interp, objv[2], + &tkBTreeDebug) != TCL_OK) { result = TCL_ERROR; goto done; } - if (textPtr->state == TK_TEXT_STATE_NORMAL) { - if (objc < 5) { - /* - * Simple case requires no predetermination of indices. - */ - CONST TkTextIndex *indexPtr1, *indexPtr2; - - /* - * Parse the starting and stopping indices. - */ + tkTextDebug = tkBTreeDebug; + } + break; + case TEXT_DELETE: + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index1 ?index2 ...?"); + result = TCL_ERROR; + goto done; + } + if (textPtr->state == TK_TEXT_STATE_NORMAL) { + if (objc < 5) { + /* + * Simple case requires no predetermination of indices. + */ + + CONST TkTextIndex *indexPtr1, *indexPtr2; + + /* + * Parse the starting and stopping indices. + */ - indexPtr1 = TkTextGetIndexFromObj(textPtr->interp, - textPtr, objv[2]); - if (indexPtr1 == NULL) { + indexPtr1 = TkTextGetIndexFromObj(textPtr->interp, textPtr, + objv[2]); + if (indexPtr1 == NULL) { + result = TCL_ERROR; + goto done; + } + if (objc == 4) { + indexPtr2 = TkTextGetIndexFromObj(textPtr->interp, textPtr, + objv[3]); + if (indexPtr2 == NULL) { result = TCL_ERROR; goto done; - } - if (objc == 4) { - indexPtr2 = TkTextGetIndexFromObj(textPtr->interp, - textPtr, objv[3]); - if (indexPtr2 == NULL) { - result = TCL_ERROR; - goto done; - } - } else { - indexPtr2 = NULL; } - DeleteChars(NULL, textPtr, indexPtr1, indexPtr2, 1); } else { - int i; - /* - * Multi-index pair case requires that we prevalidate - * the indices and sort from last to first so that - * deletes occur in the exact (unshifted) text. It - * also needs to handle partial and fully overlapping - * ranges. We have to do this with multiple passes. - */ - TkTextIndex *indices, *ixStart, *ixEnd, *lastStart; - char *useIdx; + indexPtr2 = NULL; + } + DeleteChars(NULL, textPtr, indexPtr1, indexPtr2, 1); + } else { + /* + * Multi-index pair case requires that we prevalidate the + * indices and sort from last to first so that deletes occur + * in the exact (unshifted) text. It also needs to handle + * partial and fully overlapping ranges. We have to do this + * with multiple passes. + */ + + TkTextIndex *indices, *ixStart, *ixEnd, *lastStart; + char *useIdx; + int i; - objc -= 2; - objv += 2; - indices = (TkTextIndex *) + objc -= 2; + objv += 2; + indices = (TkTextIndex *) ckalloc((objc + 1) * sizeof(TkTextIndex)); - /* - * First pass verifies that all indices are valid. - */ - for (i = 0; i < objc; i++) { - CONST TkTextIndex *indexPtr = - TkTextGetIndexFromObj(interp, textPtr, objv[i]); - - if (indexPtr == NULL) { - result = TCL_ERROR; - ckfree((char *) indices); - goto done; - } - indices[i] = *indexPtr; + /* + * First pass verifies that all indices are valid. + */ + + for (i = 0; i < objc; i++) { + CONST TkTextIndex *indexPtr = + TkTextGetIndexFromObj(interp, textPtr, objv[i]); + + if (indexPtr == NULL) { + result = TCL_ERROR; + ckfree((char *) indices); + goto done; } - /* - * Pad out the pairs evenly to make later code easier. - */ - if (objc & 1) { - indices[i] = indices[i-1]; - TkTextIndexForwChars(NULL, &indices[i], 1, &indices[i], - COUNT_INDICES); - objc++; + indices[i] = *indexPtr; + } + + /* + * Pad out the pairs evenly to make later code easier. + */ + + if (objc & 1) { + indices[i] = indices[i-1]; + TkTextIndexForwChars(NULL, &indices[i], 1, &indices[i], + COUNT_INDICES); + objc++; + } + useIdx = (char *) ckalloc((unsigned) objc); + memset(useIdx, 0, (unsigned) objc); + + /* + * Do a decreasing order sort so that we delete the end ranges + * first to maintain index consistency. + */ + + qsort((VOID *) indices, (unsigned) (objc / 2), + 2 * sizeof(TkTextIndex), TextIndexSortProc); + lastStart = NULL; + + /* + * Second pass will handle bogus ranges (end < start) and + * overlapping ranges. + */ + + for (i = 0; i < objc; i += 2) { + ixStart = &indices[i]; + ixEnd = &indices[i+1]; + if (TkTextIndexCmp(ixEnd, ixStart) <= 0) { + continue; } - useIdx = (char *) ckalloc((unsigned) objc); - memset(useIdx, 0, (unsigned) objc); - /* - * Do a decreasing order sort so that we delete the end - * ranges first to maintain index consistency. - */ - qsort((VOID *) indices, (unsigned) (objc / 2), - 2 * sizeof(TkTextIndex), TextIndexSortProc); - lastStart = NULL; - /* - * Second pass will handle bogus ranges (end < start) and - * overlapping ranges. - */ - for (i = 0; i < objc; i += 2) { - ixStart = &indices[i]; - ixEnd = &indices[i+1]; - if (TkTextIndexCmp(ixEnd, ixStart) <= 0) { + if (lastStart) { + if (TkTextIndexCmp(ixStart, lastStart) == 0) { + /* + * Start indices were equal, and the sort placed + * the longest range first, so skip this one. + */ + continue; - } - if (lastStart) { - if (TkTextIndexCmp(ixStart, lastStart) == 0) { - /* - * Start indices were equal, and the sort - * placed the longest range first, so - * skip this one. - */ + } else if (TkTextIndexCmp(lastStart, ixEnd) < 0) { + /* + * The next pair has a start range before the end + * point of the last range. Constrain the delete + * range, but use the pointer values. + */ + + *ixEnd = *lastStart; + if (TkTextIndexCmp(ixEnd, ixStart) <= 0) { continue; - } else if (TkTextIndexCmp(lastStart, ixEnd) < 0) { - /* - * The next pair has a start range before - * the end point of the last range. - * Constrain the delete range, but use - * the pointer values. - */ - *ixEnd = *lastStart; - if (TkTextIndexCmp(ixEnd, ixStart) <= 0) { - continue; - } } } - lastStart = ixStart; - useIdx[i] = 1; } - /* - * Final pass take the input from the previous and - * deletes the ranges which are flagged to be - * deleted. - */ - for (i = 0; i < objc; i += 2) { - if (useIdx[i]) { - /* - * We don't need to check the return value - * because all indices are preparsed above. - */ - DeleteChars(NULL, textPtr, &indices[i], - &indices[i+1], 1); - } + lastStart = ixStart; + useIdx[i] = 1; + } + + /* + * Final pass take the input from the previous and deletes the + * ranges which are flagged to be deleted. + */ + + for (i = 0; i < objc; i += 2) { + if (useIdx[i]) { + /* + * We don't need to check the return value because all + * indices are preparsed above. + */ + + DeleteChars(NULL, textPtr, &indices[i], &indices[i+1], + 1); } - ckfree((char *) indices); } + ckfree((char *) indices); } - break; } - case TEXT_DLINEINFO: { - int x, y, width, height, base; - CONST TkTextIndex *indexPtr; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "index"); - result = TCL_ERROR; - goto done; - } - indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); - if (indexPtr == NULL) { - result = TCL_ERROR; - goto done; - } - if (TkTextDLineInfo(textPtr, indexPtr, &x, &y, &width, - &height, &base) == 0) { - Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); - - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(x)); - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(y)); - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(width)); - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(height)); - Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewIntObj(base)); - - Tcl_SetObjResult(interp, listObj); - } - break; + break; + case TEXT_DLINEINFO: { + int x, y, width, height, base; + CONST TkTextIndex *indexPtr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + result = TCL_ERROR; + goto done; } - case TEXT_DUMP: { - result = TextDumpCmd(textPtr, interp, objc, objv); - break; + indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); + if (indexPtr == NULL) { + result = TCL_ERROR; + goto done; } - case TEXT_EDIT: { - result = TextEditCmd(textPtr, interp, objc, objv); - break; + if (TkTextDLineInfo(textPtr, indexPtr, &x, &y, &width, &height, + &base) == 0) { + Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); + + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(x)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(y)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(width)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(height)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(base)); + + Tcl_SetObjResult(interp, listObj); } - case TEXT_GET: { - Tcl_Obj *objPtr = NULL; - int i, found = 0, visible = 0; - CONST char *name; - int length; - - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, - "?-displaychars? ?--? index1 ?index2 ...?"); - result = TCL_ERROR; - goto done; + break; + } + case TEXT_DUMP: + result = TextDumpCmd(textPtr, interp, objc, objv); + break; + case TEXT_EDIT: + result = TextEditCmd(textPtr, interp, objc, objv); + break; + case TEXT_GET: { + Tcl_Obj *objPtr = NULL; + int i, found = 0, visible = 0; + CONST char *name; + int length; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-displaychars? ?--? index1 ?index2 ...?"); + result = TCL_ERROR; + goto done; + } + + /* + * Simple, restrictive argument parsing. The only options are -- and + * -displaychars (or any unique prefix). + */ + + i = 2; + if (objc > 3) { + name = Tcl_GetStringFromObj(objv[i], &length); + if (length > 1 && name[0] == '-') { + if (strncmp("-displaychars", name, (unsigned)length)==0) { + i++; + visible = 1; + name = Tcl_GetStringFromObj(objv[i], &length); + } + if ((i < objc-1) && (length == 2) && !strcmp("--", name)) { + i++; + } } - - /* - * Simple, restrictive argument parsing. The only options are -- - * and -displaychars (or any unique prefix). - */ - i = 2; - if (objc > 3) { - name = Tcl_GetStringFromObj(objv[i], &length); - if (length > 1 && name[0] == '-') { - if (strncmp("-displaychars", name, (unsigned)length)==0) { - i++; - visible = 1; - name = Tcl_GetStringFromObj(objv[i], &length); - } - if ((i < objc-1) && (length == 2) - && (strcmp("--", name) == 0)) { - i++; - } + } + + for (; i < objc; i += 2) { + CONST TkTextIndex *index1Ptr, *index2Ptr; + TkTextIndex index2; + + index1Ptr = TkTextGetIndexFromObj(interp, textPtr, objv[i]); + if (index1Ptr == NULL) { + if (objPtr) { + Tcl_DecrRefCount(objPtr); } + result = TCL_ERROR; + goto done; } - for (; i < objc; i += 2) { - CONST TkTextIndex *index1Ptr, *index2Ptr; - TkTextIndex index2; - - index1Ptr = TkTextGetIndexFromObj(interp, textPtr, objv[i]); - if (index1Ptr == NULL) { + + if (i+1 == objc) { + TkTextIndexForwChars(NULL, index1Ptr, 1, &index2, + COUNT_INDICES); + index2Ptr = &index2; + } else { + index2Ptr = TkTextGetIndexFromObj(interp, textPtr, objv[i+1]); + if (index2Ptr == NULL) { if (objPtr) { Tcl_DecrRefCount(objPtr); } result = TCL_ERROR; goto done; } - if (i+1 == objc) { - TkTextIndexForwChars(NULL, index1Ptr, - 1, &index2, COUNT_INDICES); - index2Ptr = &index2; + } + + if (TkTextIndexCmp(index1Ptr, index2Ptr) < 0) { + /* + * We want to move the text we get from the window into the + * result, but since this could in principle be a megabyte or + * more, we want to do it efficiently! + */ + + Tcl_Obj *get = TextGetText(textPtr, index1Ptr, index2Ptr, + visible); + + found++; + if (found == 1) { + Tcl_SetObjResult(interp, get); } else { - index2Ptr = TkTextGetIndexFromObj(interp, textPtr, - objv[i+1]); - if (index2Ptr == NULL) { - if (objPtr) { - Tcl_DecrRefCount(objPtr); - } - result = TCL_ERROR; - goto done; - } - } - if (TkTextIndexCmp(index1Ptr, index2Ptr) < 0) { - /* - * We want to move the text we get from the window - * into the result, but since this could in principle - * be a megabyte or more, we want to do it - * efficiently! - */ - Tcl_Obj *get = TextGetText(textPtr, index1Ptr, - index2Ptr, visible); - found++; - if (found == 1) { - Tcl_SetObjResult(interp, get); - } else { - if (found == 2) { - /* - * Move the first item we put into the result into - * the first element of the list object. - */ - objPtr = Tcl_NewObj(); - Tcl_ListObjAppendElement(NULL, objPtr, - Tcl_GetObjResult(interp)); - } - Tcl_ListObjAppendElement(NULL, objPtr, get); + if (found == 2) { + /* + * Move the first item we put into the result into the + * first element of the list object. + */ + + objPtr = Tcl_NewObj(); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_GetObjResult(interp)); } + Tcl_ListObjAppendElement(NULL, objPtr, get); } } - if (found > 1) { - Tcl_SetObjResult(interp, objPtr); - } - break; } - case TEXT_IMAGE: { - result = TkTextImageCmd(textPtr, interp, objc, objv); - break; + if (found > 1) { + Tcl_SetObjResult(interp, objPtr); + } + break; + } + case TEXT_IMAGE: + result = TkTextImageCmd(textPtr, interp, objc, objv); + break; + case TEXT_INDEX: { + CONST TkTextIndex *indexPtr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + result = TCL_ERROR; + goto done; } - case TEXT_INDEX: { - CONST TkTextIndex *indexPtr; - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "index"); - result = TCL_ERROR; - goto done; - } - - indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); - if (indexPtr == NULL) { - result = TCL_ERROR; - goto done; - } - Tcl_SetObjResult(interp, TkTextNewIndexObj(textPtr, indexPtr)); - break; + indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); + if (indexPtr == NULL) { + result = TCL_ERROR; + goto done; } - case TEXT_INSERT: { - CONST TkTextIndex *indexPtr; + Tcl_SetObjResult(interp, TkTextNewIndexObj(textPtr, indexPtr)); + break; + } + case TEXT_INSERT: { + CONST TkTextIndex *indexPtr; - if (objc < 4) { - Tcl_WrongNumArgs(interp, 2, objv, - "index chars ?tagList chars tagList ...?"); - result = TCL_ERROR; - goto done; - } - indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); - if (indexPtr == NULL) { - result = TCL_ERROR; - goto done; - } - if (textPtr->state == TK_TEXT_STATE_NORMAL) { - result = TextInsertCmd(NULL, textPtr, interp, - objc-3, objv+3, - indexPtr, 1); - } - break; + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, + "index chars ?tagList chars tagList ...?"); + result = TCL_ERROR; + goto done; } - case TEXT_MARK: { - result = TkTextMarkCmd(textPtr, interp, objc, objv); - break; + indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); + if (indexPtr == NULL) { + result = TCL_ERROR; + goto done; } - case TEXT_PEER: { - result = TextPeerCmd(textPtr, interp, objc, objv); - break; + if (textPtr->state == TK_TEXT_STATE_NORMAL) { + result = TextInsertCmd(NULL, textPtr, interp, objc-3, objv+3, + indexPtr, 1); + } + break; + } + case TEXT_MARK: + result = TkTextMarkCmd(textPtr, interp, objc, objv); + break; + case TEXT_PEER: + result = TextPeerCmd(textPtr, interp, objc, objv); + break; + case TEXT_REPLACE: { + CONST TkTextIndex *indexFromPtr, *indexToPtr; + + if (objc < 5) { + Tcl_WrongNumArgs(interp, 2, objv, + "index1 index2 chars ?tagList chars tagList ...?"); + result = TCL_ERROR; + goto done; + } + indexFromPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); + if (indexFromPtr == NULL) { + result = TCL_ERROR; + goto done; } - case TEXT_REPLACE: { - CONST TkTextIndex *indexFromPtr, *indexToPtr; + indexToPtr = TkTextGetIndexFromObj(interp, textPtr, objv[3]); + if (indexToPtr == NULL) { + result = TCL_ERROR; + goto done; + } + if (TkTextIndexCmp(indexFromPtr, indexToPtr) > 0) { + Tcl_AppendResult(interp, "Index \"", Tcl_GetString(objv[3]), + "\" before \"", Tcl_GetString(objv[2]), + "\" in the text", NULL); + result = TCL_ERROR; + goto done; + } + if (textPtr->state == TK_TEXT_STATE_NORMAL) { + int lineNum, byteIndex; + TkTextIndex index; - if (objc < 5) { - Tcl_WrongNumArgs(interp, 2, objv, - "index1 index2 chars ?tagList chars tagList ...?"); - result = TCL_ERROR; - goto done; - } - indexFromPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]); - if (indexFromPtr == NULL) { - result = TCL_ERROR; - goto done; - } - indexToPtr = TkTextGetIndexFromObj(interp, textPtr, objv[3]); - if (indexToPtr == NULL) { - result = TCL_ERROR; - goto done; - } - if (TkTextIndexCmp(indexFromPtr, indexToPtr) > 0) { - Tcl_AppendResult(interp, "Index \"", Tcl_GetString(objv[3]), - "\" before \"", Tcl_GetString(objv[2]), - "\" in the text.", NULL); - result = TCL_ERROR; - goto done; - } - if (textPtr->state == TK_TEXT_STATE_NORMAL) { - int lineNum, byteIndex; - TkTextIndex index; + /* + * The 'replace' operation is quite complex to do correctly, + * because we want a number of criteria to hold: + * + * 1. The insertion point shouldn't move, unless it is within the + * deleted range. In this case it should end up after the new + * text. + * + * 2. The window should not change the text it shows - should not + * scroll vertically - unless the result of the replace is + * that the insertion position which used to be on-screen is + * now off-screen. + */ + + byteIndex = textPtr->topIndex.byteIndex; + lineNum = TkBTreeLinesTo(textPtr, textPtr->topIndex.linePtr); + + TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); + if ((TkTextIndexCmp(indexFromPtr, &index) < 0) + && (TkTextIndexCmp(indexToPtr, &index) > 0)) { /* - * The 'replace' operation is quite complex to do - * correctly, because we want a number of criteria - * to hold: - * - * 1. The insertion point shouldn't move, unless - * it is within the deleted range. In this case - * it should end up after the new text. - * - * 2. The window should not change the text it - * shows -- should not scroll vertically -- unless - * the result of the replace is that the insertion - * position which used to be on-screen is now - * off-screen. + * The insertion point is inside the range to be replaced, so + * we have to do some calculations to ensure it doesn't move + * unnecessarily. */ - byteIndex = textPtr->topIndex.byteIndex; - lineNum = TkBTreeLinesTo(textPtr, textPtr->topIndex.linePtr); - TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, - &index); - if ((TkTextIndexCmp(indexFromPtr, &index) < 0) - && (TkTextIndexCmp(indexToPtr, &index) > 0)) { - /* - * The insertion point is inside the range to be - * replaced, so we have to do some calculations to - * ensure it doesn't move unnecessarily. - */ - int deleteInsertOffset, insertLength, j; - - insertLength = 0; - for (j = 4; j < objc; j += 2) { - insertLength += Tcl_GetCharLength(objv[j]); - } - - /* - * Calculate 'deleteInsertOffset' as an offset we - * will apply to the insertion point after this - * operation. - */ - deleteInsertOffset = CountIndices(textPtr, indexFromPtr, - &index, COUNT_CHARS); - if (deleteInsertOffset > insertLength) { - deleteInsertOffset = insertLength; - } - - result = TextReplaceCmd(textPtr, interp, - indexFromPtr, indexToPtr, - objc, objv, 0); - - if (result == TCL_OK) { - /* - * Move the insertion position to the correct - * place - */ - TkTextIndexForwChars(NULL, indexFromPtr, - deleteInsertOffset, - &index, COUNT_INDICES); - TkBTreeUnlinkSegment(textPtr->insertMarkPtr, - textPtr->insertMarkPtr->body.mark.linePtr); - TkBTreeLinkSegment(textPtr->insertMarkPtr, &index); - } - } else { - result = TextReplaceCmd(textPtr, interp, - indexFromPtr, indexToPtr, - objc, objv, 1); + int deleteInsertOffset, insertLength, j; + + insertLength = 0; + for (j = 4; j < objc; j += 2) { + insertLength += Tcl_GetCharLength(objv[j]); + } + + /* + * Calculate 'deleteInsertOffset' as an offset we will apply + * to the insertion point after this operation. + */ + + deleteInsertOffset = CountIndices(textPtr, indexFromPtr, + &index, COUNT_CHARS); + if (deleteInsertOffset > insertLength) { + deleteInsertOffset = insertLength; } + + result = TextReplaceCmd(textPtr, interp, indexFromPtr, + indexToPtr, objc, objv, 0); + if (result == TCL_OK) { - /* - * Now ensure the top-line is in the right - * place + /* + * Move the insertion position to the correct place. */ - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, - textPtr, lineNum, - byteIndex, &index); - TkTextSetYView(textPtr, &index, TK_TEXT_NOPIXELADJUST); + + TkTextIndexForwChars(NULL, indexFromPtr, + deleteInsertOffset, &index, COUNT_INDICES); + TkBTreeUnlinkSegment(textPtr->insertMarkPtr, + textPtr->insertMarkPtr->body.mark.linePtr); + TkBTreeLinkSegment(textPtr->insertMarkPtr, &index); } + } else { + result = TextReplaceCmd(textPtr, interp, indexFromPtr, + indexToPtr, objc, objv, 1); + } + if (result == TCL_OK) { + /* + * Now ensure the top-line is in the right place. + */ + + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + lineNum, byteIndex, &index); + TkTextSetYView(textPtr, &index, TK_TEXT_NOPIXELADJUST); } - break; - } - case TEXT_SCAN: { - result = TkTextScanCmd(textPtr, interp, objc, objv); - break; - } - case TEXT_SEARCH: { - result = TextSearchCmd(textPtr, interp, objc, objv); - break; - } - case TEXT_SEE: { - result = TkTextSeeCmd(textPtr, interp, objc, objv); - break; - } - case TEXT_TAG: { - result = TkTextTagCmd(textPtr, interp, objc, objv); - break; - } - case TEXT_WINDOW: { - result = TkTextWindowCmd(textPtr, interp, objc, objv); - break; - } - case TEXT_XVIEW: { - result = TkTextXviewCmd(textPtr, interp, objc, objv); - break; - } - case TEXT_YVIEW: { - result = TkTextYviewCmd(textPtr, interp, objc, objv); - break; } - } - - done: + break; + } + case TEXT_SCAN: + result = TkTextScanCmd(textPtr, interp, objc, objv); + break; + case TEXT_SEARCH: + result = TextSearchCmd(textPtr, interp, objc, objv); + break; + case TEXT_SEE: + result = TkTextSeeCmd(textPtr, interp, objc, objv); + break; + case TEXT_TAG: + result = TkTextTagCmd(textPtr, interp, objc, objv); + break; + case TEXT_WINDOW: + result = TkTextWindowCmd(textPtr, interp, objc, objv); + break; + case TEXT_XVIEW: + result = TkTextXviewCmd(textPtr, interp, objc, objv); + break; + case TEXT_YVIEW: + result = TkTextYviewCmd(textPtr, interp, objc, objv); + break; + } + + done: textPtr->refCount--; if (textPtr->refCount == 0) { ckfree((char *) textPtr); @@ -1502,12 +1490,11 @@ TextWidgetObjCmd(clientData, interp, objc, objv) * * SharedTextObjCmd -- * - * This procedure is invoked to process commands on the shared - * portion of a text widget. Currently it is not actually exported - * as a Tcl command, and is only used internally to process parts - * of undo/redo scripts. See the user documentation for 'text' for - * details on what it does - the only subcommands it currently - * supports are 'insert' and 'delete'. + * This function is invoked to process commands on the shared portion of + * a text widget. Currently it is not actually exported as a Tcl command, + * and is only used internally to process parts of undo/redo scripts. + * See the user documentation for 'text' for details on what it does - + * the only subcommands it currently supports are 'insert' and 'delete'. * * Results: * A standard Tcl result. @@ -1520,8 +1507,7 @@ TextWidgetObjCmd(clientData, interp, objc, objv) static int SharedTextObjCmd(clientData, interp, objc, objv) - ClientData clientData; /* Information about shared test - * B-tree. */ + ClientData clientData; /* Information about shared test B-tree. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ @@ -1529,14 +1515,14 @@ SharedTextObjCmd(clientData, interp, objc, objv) register TkSharedText *sharedPtr = (TkSharedText *) clientData; int result = TCL_OK; int index; - + static CONST char *optionStrings[] = { - "delete", "insert", (char *) NULL + "delete", "insert", (char *) NULL }; enum options { TEXT_DELETE, TEXT_INSERT }; - + if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; @@ -1548,65 +1534,64 @@ SharedTextObjCmd(clientData, interp, objc, objv) } switch ((enum options) index) { - case TEXT_DELETE: { - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "index1 ?index2 ...?"); - result = TCL_ERROR; - goto done; + case TEXT_DELETE: + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index1 ?index2 ...?"); + return TCL_ERROR; + } + if (objc < 5) { + /* + * Simple case requires no predetermination of indices. + */ + + TkTextIndex index1; + + /* + * Parse the starting and stopping indices. + */ + + result = TkTextSharedGetObjIndex(interp, sharedPtr, objv[2], + &index1); + if (result != TCL_OK) { + return result; } - if (objc < 5) { - /* - * Simple case requires no predetermination of indices. - */ - TkTextIndex index1; - - /* - * Parse the starting and stopping indices. - */ + if (objc == 4) { + TkTextIndex index2; - result = TkTextSharedGetObjIndex(interp, sharedPtr, - objv[2], &index1); + result = TkTextSharedGetObjIndex(interp, sharedPtr, objv[3], + &index2); if (result != TCL_OK) { - goto done; - } - if (objc == 4) { - TkTextIndex index2; - result = TkTextSharedGetObjIndex(interp, sharedPtr, - objv[3], &index2); - if (result != TCL_OK) { - goto done; - } - DeleteChars(sharedPtr, NULL, &index1, &index2, 1); - } else { - DeleteChars(sharedPtr, NULL, &index1, NULL, 1); + return result; } + DeleteChars(sharedPtr, NULL, &index1, &index2, 1); } else { - /* Too many arguments */ - result = TCL_ERROR; + DeleteChars(sharedPtr, NULL, &index1, NULL, 1); } - break; + return TCL_OK; + } else { + /* Too many arguments */ + return TCL_ERROR; } - case TEXT_INSERT: { - TkTextIndex index1; - if (objc < 4) { - Tcl_WrongNumArgs(interp, 2, objv, - "index chars ?tagList chars tagList ...?"); - result = TCL_ERROR; - goto done; - } - result = TkTextSharedGetObjIndex(interp, sharedPtr, - objv[2], &index1); - if (result != TCL_OK) { - goto done; - } - result = TextInsertCmd(sharedPtr, NULL, interp, objc-3, objv+3, - &index1, 1); - break; + break; + case TEXT_INSERT: { + TkTextIndex index1; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, + "index chars ?tagList chars tagList ...?"); + return TCL_ERROR; } + result = TkTextSharedGetObjIndex(interp, sharedPtr, objv[2], + &index1); + if (result != TCL_OK) { + return result; + } + return TextInsertCmd(sharedPtr, NULL, interp, objc-3, objv+3, &index1, + 1); + } + default: + return TCL_OK; } - - done: - return result; } /* @@ -1614,9 +1599,8 @@ SharedTextObjCmd(clientData, interp, objc, objv) * * TextPeerCmd -- * - * This procedure is invoked to process the "text peer" Tcl - * command. See the user documentation for details on what it - * does. + * This function is invoked to process the "text peer" Tcl command. See + * the user documentation for details on what it does. * * Results: * A standard Tcl result. @@ -1629,16 +1613,16 @@ SharedTextObjCmd(clientData, interp, objc, objv) static int TextPeerCmd(textPtr, interp, objc, objv) - TkText *textPtr; /* Information about text widget. */ + TkText *textPtr; /* Information about text widget. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tk_Window tkwin = textPtr->tkwin; int index; - + static CONST char *peerOptionStrings[] = { - "create", "names", (char *) NULL + "create", "names", (char *) NULL }; enum peerOptions { PEER_CREATE, PEER_NAMES @@ -1648,35 +1632,35 @@ TextPeerCmd(textPtr, interp, objc, objv) Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?"); return TCL_ERROR; } - - if (Tcl_GetIndexFromObj(interp, objv[2], peerOptionStrings, - "peer option", 0, &index) != TCL_OK) { + + if (Tcl_GetIndexFromObj(interp, objv[2], peerOptionStrings, + "peer option", 0, &index) != TCL_OK) { return TCL_ERROR; } - + switch ((enum peerOptions)index) { - case PEER_CREATE: { - if (objc < 4) { - Tcl_WrongNumArgs(interp, 3, objv, "pathName ?options?"); - return TCL_ERROR; - } - return CreateWidget(textPtr->sharedTextPtr, tkwin, - interp, textPtr, objc-2, objv+2); + case PEER_CREATE: + if (objc < 4) { + Tcl_WrongNumArgs(interp, 3, objv, "pathName ?options?"); + return TCL_ERROR; } - case PEER_NAMES: { - TkText *tPtr = textPtr->sharedTextPtr->peers; - if (objc > 3) { - Tcl_WrongNumArgs(interp, 3, objv, NULL); - return TCL_ERROR; - } - while (tPtr != NULL) { - if (tPtr != textPtr) { - Tcl_AppendElement(interp, Tk_PathName(tPtr->tkwin)); - } - tPtr = tPtr->next; + return CreateWidget(textPtr->sharedTextPtr, tkwin, interp, textPtr, + objc-2, objv+2); + case PEER_NAMES: { + TkText *tPtr = textPtr->sharedTextPtr->peers; + + if (objc > 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; + } + while (tPtr != NULL) { + if (tPtr != textPtr) { + Tcl_AppendElement(interp, Tk_PathName(tPtr->tkwin)); } + tPtr = tPtr->next; } } + } return TCL_OK; } @@ -1686,7 +1670,7 @@ TextPeerCmd(textPtr, interp, objc, objv) * * TextReplaceCmd -- * - * This procedure is invoked to process part of the "replace" widget + * This function is invoked to process part of the "replace" widget * command for text widgets. * * Results: @@ -1694,53 +1678,55 @@ TextPeerCmd(textPtr, interp, objc, objv) * * Side effects: * See the user documentation. - * - * If 'viewUpdate' is false, then textPtr->topIndex may no longer - * be a valid index after this function returns. The caller is - * responsible for ensuring a correct index is in place. + * + * If 'viewUpdate' is false, then textPtr->topIndex may no longer be a + * valid index after this function returns. The caller is responsible for + * ensuring a correct index is in place. * *---------------------------------------------------------------------- */ static int -TextReplaceCmd(textPtr, interp, indexFromPtr, indexToPtr, - objc, objv, viewUpdate) - TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - CONST TkTextIndex *indexFromPtr;/* Index from which to replace */ - CONST TkTextIndex *indexToPtr; /* Index to which to replace */ - int objc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects. */ - int viewUpdate; /* Update vertical view if set. */ +TextReplaceCmd(textPtr, interp, indexFromPtr, indexToPtr, objc, objv, + viewUpdate) + TkText *textPtr; /* Information about text widget. */ + Tcl_Interp *interp; /* Current interpreter. */ + CONST TkTextIndex *indexFromPtr; + /* Index from which to replace */ + CONST TkTextIndex *indexToPtr; + /* Index to which to replace */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ + int viewUpdate; /* Update vertical view if set. */ { - int result; /* - * Perform the deletion and insertion, but ensure - * no undo-separator is placed between the two - * operations. Since we are using the helper procedures - * 'DeleteChars' and 'TextInsertCmd' we have to pretend - * that the autoSeparators setting is off, so that we don't - * get an undo-separator between the delete and insert. + * Perform the deletion and insertion, but ensure no undo-separator is + * placed between the two operations. Since we are using the helper + * functions 'DeleteChars' and 'TextInsertCmd' we have to pretend that the + * autoSeparators setting is off, so that we don't get an undo-separator + * between the delete and insert. */ + int origAutoSep = textPtr->sharedTextPtr->autoSeparators; + int result; if (textPtr->sharedTextPtr->undo) { textPtr->sharedTextPtr->autoSeparators = 0; - if (origAutoSep - && textPtr->sharedTextPtr->lastEditMode != TK_TEXT_EDIT_REPLACE) { + if (origAutoSep && + textPtr->sharedTextPtr->lastEditMode != TK_TEXT_EDIT_REPLACE) { TkUndoInsertUndoSeparator(textPtr->sharedTextPtr->undoStack); } } DeleteChars(NULL, textPtr, indexFromPtr, indexToPtr, viewUpdate); - result = TextInsertCmd(NULL, textPtr, interp, objc-4, objv+4, - indexFromPtr, viewUpdate); + result = TextInsertCmd(NULL, textPtr, interp, objc-4, objv+4, + indexFromPtr, viewUpdate); if (textPtr->sharedTextPtr->undo) { - textPtr->sharedTextPtr->lastEditMode = TK_TEXT_EDIT_REPLACE; + textPtr->sharedTextPtr->lastEditMode = TK_TEXT_EDIT_REPLACE; textPtr->sharedTextPtr->autoSeparators = origAutoSep; } - + return result; } @@ -1749,13 +1735,13 @@ TextReplaceCmd(textPtr, interp, indexFromPtr, indexToPtr, * * TextIndexSortProc -- * - * This procedure is called by qsort when sorting an array of - * indices in *decreasing* order (last to first). + * This function is called by qsort when sorting an array of indices in + * *decreasing* order (last to first). * * Results: - * The return value is -1 if the first argument should be before - * the second element, 0 if it's equivalent, and 1 if it should be - * after the second element. + * The return value is -1 if the first argument should be before the + * second element, 0 if it's equivalent, and 1 if it should be after the + * second element. * * Side effects: * None. @@ -1774,9 +1760,10 @@ TextIndexSortProc(first, second) if (cmp == 0) { /* * If the first indices were equal, we want the second index of the - * pair also to be the greater. Use pointer magic to access the - * second index pair. + * pair also to be the greater. Use pointer magic to access the second + * index pair. */ + cmp = TkTextIndexCmp(&pair1[0], &pair2[0]); } if (cmp > 0) { @@ -1792,20 +1779,20 @@ TextIndexSortProc(first, second) * * DestroyText -- * - * This procedure is invoked when we receive a destroy event - * to clean up the internal structure of a text widget. We will - * free up most of the internal structure and delete the - * associated Tcl command. If there are no outstanding - * references to the widget, we also free up the textPtr itself. - * + * This function is invoked when we receive a destroy event to clean up + * the internal structure of a text widget. We will free up most of the + * internal structure and delete the associated Tcl command. If there are + * no outstanding references to the widget, we also free up the textPtr + * itself. + * * The widget has already been flagged as deleted. * * Results: * None. * * Side effects: - * Either everything or almost everything associated with the - * text is freed up. + * Either everything or almost everything associated with the text is + * freed up. * *---------------------------------------------------------------------- */ @@ -1818,22 +1805,22 @@ DestroyText(textPtr) Tcl_HashEntry *hPtr; TkTextTag *tagPtr; TkSharedText *sharedTextPtr = textPtr->sharedTextPtr; - + /* - * Free up all the stuff that requires special handling. We have - * already called let Tk_FreeConfigOptions to handle all the standard - * option-related stuff (and so none of that exists when we are - * called). Special note: free up display-related information before - * deleting the B-tree, since display-related stuff may refer to - * stuff in the B-tree. + * Free up all the stuff that requires special handling. We have already + * called let Tk_FreeConfigOptions to handle all the standard + * option-related stuff (and so none of that exists when we are called). + * Special note: free up display-related information before deleting the + * B-tree, since display-related stuff may refer to stuff in the B-tree. */ TkTextFreeDInfo(textPtr); textPtr->dInfoPtr = NULL; - + /* * Remove ourselves from the peer list */ + if (sharedTextPtr->peers == textPtr) { sharedTextPtr->peers = textPtr->next; } else { @@ -1847,52 +1834,55 @@ DestroyText(textPtr) } } - /* - * Always clean up the widget-specific tags first. Common tags - * (i.e. most) will only be cleaned up when the shared structure - * is cleaned up. - * - * We also need to clean up widget-specific marks ('insert', - * 'current'), since otherwise marks will never disappear from - * the B-tree. + /* + * Always clean up the widget-specific tags first. Common tags (i.e. most) + * will only be cleaned up when the shared structure is cleaned up. + * + * We also need to clean up widget-specific marks ('insert', 'current'), + * since otherwise marks will never disappear from the B-tree. */ - + TkTextDeleteTag(textPtr, textPtr->selTagPtr); TkBTreeUnlinkSegment(textPtr->insertMarkPtr, - textPtr->insertMarkPtr->body.mark.linePtr); + textPtr->insertMarkPtr->body.mark.linePtr); ckfree((char *) textPtr->insertMarkPtr); TkBTreeUnlinkSegment(textPtr->currentMarkPtr, - textPtr->currentMarkPtr->body.mark.linePtr); + textPtr->currentMarkPtr->body.mark.linePtr); ckfree((char *) textPtr->currentMarkPtr); - /* - * Now we've cleaned up everything of relevance to us in the B-tree, - * so we disassociate outselves from it. - * - * When the refCount reaches zero, it's time to clean up - * the shared portion of the text widget - */ + /* + * Now we've cleaned up everything of relevance to us in the B-tree, so we + * disassociate outselves from it. + * + * When the refCount reaches zero, it's time to clean up the shared + * portion of the text widget + */ + sharedTextPtr->refCount--; - + if (sharedTextPtr->refCount > 0) { TkBTreeRemoveClient(sharedTextPtr->tree, textPtr); - - /* Free up any embedded windows which belong to this widget. */ + + /* + * Free up any embedded windows which belong to this widget. + */ + for (hPtr = Tcl_FirstHashEntry(&sharedTextPtr->windowTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { TkTextEmbWindowClient *loop; TkTextSegment *ewPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr); - + loop = ewPtr->body.ew.clients; if (loop->textPtr == textPtr) { ewPtr->body.ew.clients = loop->next; TkTextWinFreeClient(hPtr, loop); } else { TkTextEmbWindowClient *client = ewPtr->body.ew.clients; + client = loop->next; while (client != NULL) { if (client->textPtr == textPtr) { - loop->next = client->next; + loop->next = client->next; TkTextWinFreeClient(hPtr, client); break; } else { @@ -1903,19 +1893,22 @@ DestroyText(textPtr) } } } else { - /* - * No need to call 'TkBTreeRemoveClient' first, since this - * will do everything in one go, more quickly. + /* + * No need to call 'TkBTreeRemoveClient' first, since this will do + * everything in one go, more quickly. */ + TkBTreeDestroy(sharedTextPtr->tree); - + for (hPtr = Tcl_FirstHashEntry(&sharedTextPtr->tagTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); - /* - * No need to use 'TkTextDeleteTag' since we've already - * removed the B-tree completely + + /* + * No need to use 'TkTextDeleteTag' since we've already removed + * the B-tree completely */ + TkTextFreeTag(textPtr, tagPtr); } Tcl_DeleteHashTable(&sharedTextPtr->tagTable); @@ -1925,15 +1918,15 @@ DestroyText(textPtr) } Tcl_DeleteHashTable(&sharedTextPtr->markTable); TkUndoFreeStack(sharedTextPtr->undoStack); - + Tcl_DeleteHashTable(&sharedTextPtr->windowTable); Tcl_DeleteHashTable(&sharedTextPtr->imageTable); - + if (sharedTextPtr->bindingTable != NULL) { Tk_DeleteBindingTable(sharedTextPtr->bindingTable); } } - + if (textPtr->tabArrayPtr != NULL) { ckfree((char *) textPtr->tabArrayPtr); } @@ -1945,7 +1938,7 @@ DestroyText(textPtr) textPtr->refCount--; Tcl_DeleteCommandFromToken(textPtr->interp, textPtr->widgetCmd); if (textPtr->refCount == 0) { - ckfree((char *) textPtr); + ckfree((char *) textPtr); } } @@ -1954,18 +1947,16 @@ DestroyText(textPtr) * * ConfigureText -- * - * This procedure is called to process an objv/objc list, plus - * the Tk option database, in order to configure (or - * reconfigure) a text widget. + * This function is called to process an objv/objc list, plus the Tk + * option database, in order to configure (or reconfigure) a text widget. * * Results: - * The return value is a standard Tcl result. If TCL_ERROR is - * returned, then the interp's result contains an error message. + * The return value is a standard Tcl result. If TCL_ERROR is returned, + * then the interp's result contains an error message. * * Side effects: - * Configuration information, such as text string, colors, font, - * etc. get set for textPtr; old resources get freed, if there - * were any. + * Configuration information, such as text string, colors, font, etc. get + * set for textPtr; old resources get freed, if there were any. * *---------------------------------------------------------------------- */ @@ -1973,8 +1964,8 @@ DestroyText(textPtr) static int ConfigureText(interp, textPtr, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ - register TkText *textPtr; /* Information about widget; may or may - * not already have values for some fields. */ + register TkText *textPtr; /* Information about widget; may or may not + * already have values for some fields. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { @@ -1987,32 +1978,34 @@ ConfigureText(interp, textPtr, objc, objv) return TCL_ERROR; } - /* - * Copy down shared flags + /* + * Copy down shared flags. */ + textPtr->sharedTextPtr->undo = textPtr->undo; textPtr->sharedTextPtr->maxUndo = textPtr->maxUndo; textPtr->sharedTextPtr->autoSeparators = textPtr->autoSeparators; - TkUndoSetDepth(textPtr->sharedTextPtr->undoStack, - textPtr->sharedTextPtr->maxUndo); + TkUndoSetDepth(textPtr->sharedTextPtr->undoStack, + textPtr->sharedTextPtr->maxUndo); /* - * A few other options also need special processing, such as parsing - * the geometry and setting the background from a 3-D border. + * A few other options also need special processing, such as parsing the + * geometry and setting the background from a 3-D border. */ Tk_SetBackgroundFromBorder(textPtr->tkwin, textPtr->border); if (mask & TK_TEXT_LINE_RANGE) { int start, end, current; - - /* - * Line start and/or end have been adjusted. We need to validate - * the first displayed line and arrange for re-layout. + + /* + * Line start and/or end have been adjusted. We need to validate the + * first displayed line and arrange for re-layout. */ + TkBTreeClientRangeChanged(textPtr, textPtr->charHeight); - + if (textPtr->start != NULL) { start = TkBTreeLinesTo(NULL, textPtr->start); } else { @@ -2024,7 +2017,8 @@ ConfigureText(interp, textPtr, objc, objv) end = TkBTreeNumLines(textPtr->sharedTextPtr->tree, NULL); } if (start > end) { - Tcl_AppendResult(interp, "-startline must be less than or equal to -endline", NULL); + Tcl_AppendResult(interp, + "-startline must be less than or equal to -endline", NULL); Tk_RestoreSavedOptions(&savedOptions); return TCL_ERROR; } @@ -2033,22 +2027,25 @@ ConfigureText(interp, textPtr, objc, objv) TkTextSearch search; TkTextIndex index1, first, last; int selChanged = 0; - - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, - start, 0, &index1); + + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, start, 0, + &index1); TkTextSetYView(textPtr, &index1, 0); - /* - * We may need to adjust the selection. So we have to - * check whether the "sel" tag was applied to anything - * outside the current start,end. + + /* + * We may need to adjust the selection. So we have to check + * whether the "sel" tag was applied to anything outside the + * current start,end. */ - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, 0, 0, &first); - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, - TkBTreeNumLines(textPtr->sharedTextPtr->tree, NULL), - 0, &last); + + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, 0, 0, + &first); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, NULL), + &last); TkBTreeStartSearch(&first, &last, textPtr->selTagPtr, &search); - if (!TkBTreeCharTagged(&first, textPtr->selTagPtr) - && !TkBTreeNextTag(&search)) { + if (!TkBTreeCharTagged(&first, textPtr->selTagPtr) + && !TkBTreeNextTag(&search)) { /* Nothing tagged with "sel" */ } else { int line = TkBTreeLinesTo(NULL, search.curIndex.linePtr); @@ -2056,26 +2053,28 @@ ConfigureText(interp, textPtr, objc, objv) selChanged = 1; } else { TkTextLine *linePtr = search.curIndex.linePtr; + while (TkBTreeNextTag(&search)) { linePtr = search.curIndex.linePtr; } line = TkBTreeLinesTo(NULL, linePtr); if (line >= end) { - selChanged = 1; + selChanged = 1; } } } if (selChanged) { - /* - * Send an event that the selection has changed, and - * abort any partial-selections in progress. + /* + * Send an event that the selection has changed, and abort any + * partial-selections in progress. */ + TkTextSelectionEvent(textPtr); textPtr->abortSelections = 1; } } } - + /* * Don't allow negative spacings. */ @@ -2109,11 +2108,10 @@ ConfigureText(interp, textPtr, objc, objv) } /* - * Make sure that configuration options are properly mirrored - * between the widget record and the "sel" tags. NOTE: we don't - * have to free up information during the mirroring; old - * information was freed when it was replaced in the widget - * record. + * Make sure that configuration options are properly mirrored between the + * widget record and the "sel" tags. NOTE: we don't have to free up + * information during the mirroring; old information was freed when it was + * replaced in the widget record. */ textPtr->selTagPtr->border = textPtr->selBorder; @@ -2160,9 +2158,11 @@ ConfigureText(interp, textPtr, objc, objv) TkTextSearch search; TkTextIndex first, last; - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0, &first); - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), 0, &last); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0, + &first); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), + 0, &last); TkBTreeStartSearch(&first, &last, textPtr->selTagPtr, &search); if (TkBTreeCharTagged(&first, textPtr->selTagPtr) || TkBTreeNextTag(&search)) { @@ -2183,8 +2183,8 @@ ConfigureText(interp, textPtr, objc, objv) } /* - * Register the desired geometry for the window, and arrange for - * the window to be redisplayed. + * Register the desired geometry for the window, and arrange for the + * window to be redisplayed. */ if (textPtr->width <= 0) { @@ -2203,21 +2203,21 @@ ConfigureText(interp, textPtr, objc, objv) * * TextWorldChangedCallback -- * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. + * This function is called when the world has changed in some way and the + * widget needs to recompute all its graphics contexts and determine its + * new geometry. * * Results: - * None. + * None. * * Side effects: - * Configures all tags in the Text with a empty objc/objv, for - * the side effect of causing all the items to recompute their - * geometry and to be redisplayed. + * Configures all tags in the Text with a empty objc/objv, for the side + * effect of causing all the items to recompute their geometry and to be + * redisplayed. * *--------------------------------------------------------------------------- */ - + static void TextWorldChangedCallback(instanceData) ClientData instanceData; /* Information about widget. */ @@ -2233,30 +2233,29 @@ TextWorldChangedCallback(instanceData) * * TextWorldChanged -- * - * This procedure is called when the world has changed in some - * way and the widget needs to recompute all its graphics contexts - * and determine its new geometry. + * This function is called when the world has changed in some way and the + * widget needs to recompute all its graphics contexts and determine its + * new geometry. * * Results: - * None. + * None. * * Side effects: - * Configures all tags in the Text with a empty objc/objv, for - * the side effect of causing all the items to recompute their - * geometry and to be redisplayed. + * Configures all tags in the Text with a empty objc/objv, for the side + * effect of causing all the items to recompute their geometry and to be + * redisplayed. * *--------------------------------------------------------------------------- */ - + static void TextWorldChanged(textPtr, mask) TkText *textPtr; /* Information about widget. */ - int mask; /* OR'd collection of bits showing what - * has changed */ + int mask; /* OR'd collection of bits showing what has changed */ { Tk_FontMetrics fm; int border; - + textPtr->charWidth = Tk_TextWidth(textPtr->tkfont, "0", 1); if (textPtr->charWidth <= 0) { textPtr->charWidth = 1; @@ -2269,15 +2268,13 @@ TextWorldChanged(textPtr, mask) } border = textPtr->borderWidth + textPtr->highlightWidth; Tk_GeometryRequest(textPtr->tkwin, - textPtr->width * textPtr->charWidth - + 2*textPtr->padX + 2*border, - textPtr->height * (fm.linespace + textPtr->spacing1 - + textPtr->spacing3) + textPtr->width * textPtr->charWidth + 2*textPtr->padX + 2*border, + textPtr->height* (fm.linespace+textPtr->spacing1+textPtr->spacing3) + 2*textPtr->padY + 2*border); - Tk_SetInternalBorderEx(textPtr->tkwin, - border + textPtr->padX, border + textPtr->padX, - border + textPtr->padY, border + textPtr->padY); + Tk_SetInternalBorderEx(textPtr->tkwin, + border + textPtr->padX, border + textPtr->padX, + border + textPtr->padY, border + textPtr->padY); if (textPtr->setGrid) { Tk_SetGrid(textPtr->tkwin, textPtr->width, textPtr->height, textPtr->charWidth, textPtr->charHeight); @@ -2293,16 +2290,16 @@ TextWorldChanged(textPtr, mask) * * TextEventProc -- * - * This procedure is invoked by the Tk dispatcher on - * structure changes to a text. For texts with 3D - * borders, this procedure is also invoked for exposures. + * This function is invoked by the Tk dispatcher on structure changes to + * a text. For texts with 3D borders, this function is also invoked for + * exposures. * * Results: * None. * * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. + * When the window gets deleted, internal structures get cleaned up. + * When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ @@ -2323,8 +2320,9 @@ TextEventProc(clientData, eventPtr) if ((textPtr->prevWidth != Tk_Width(textPtr->tkwin)) || (textPtr->prevHeight != Tk_Height(textPtr->tkwin))) { int mask = 0; + if (textPtr->prevWidth != Tk_Width(textPtr->tkwin)) { - mask = TK_TEXT_LINE_GEOMETRY; + mask = TK_TEXT_LINE_GEOMETRY; } TkTextRelayoutWindow(textPtr, mask); textPtr->prevWidth = Tk_Width(textPtr->tkwin); @@ -2333,12 +2331,12 @@ TextEventProc(clientData, eventPtr) } else if (eventPtr->type == DestroyNotify) { /* * NOTE: we must zero out selBorder, selBorderWidthPtr and - * selFgColorPtr: they are duplicates of information in the - * "sel" tag, which will be freed up when we delete all tags. - * Hence we don't want the automatic config options freeing - * process to delete them as well. + * selFgColorPtr: they are duplicates of information in the "sel" tag, + * which will be freed up when we delete all tags. Hence we don't want + * the automatic config options freeing process to delete them as + * well. */ - + textPtr->selBorder = NULL; textPtr->selBorderWidthPtr = NULL; textPtr->selBorderWidth = 0; @@ -2349,24 +2347,23 @@ TextEventProc(clientData, eventPtr) } if (!(textPtr->flags & OPTIONS_FREED)) { Tk_FreeConfigOptions((char *) textPtr, textPtr->optionTable, - textPtr->tkwin); + textPtr->tkwin); textPtr->flags |= OPTIONS_FREED; } textPtr->flags |= DESTROYED; - - /* - * Call 'DestroyTest' to handle the deletion for us. The - * actual textPtr may still exist after this, if there are - * some outstanding references. But we have flagged it - * as DESTROYED just above, so nothing will try to make use - * of it very extensively. + + /* + * Call 'DestroyTest' to handle the deletion for us. The actual + * textPtr may still exist after this, if there are some outstanding + * references. But we have flagged it as DESTROYED just above, so + * nothing will try to make use of it very extensively. */ + DestroyText(textPtr); } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { if (eventPtr->xfocus.detail == NotifyInferior - || eventPtr->xfocus.detail == NotifyAncestor - || eventPtr->xfocus.detail == NotifyNonlinear - ) { + || eventPtr->xfocus.detail == NotifyAncestor + || eventPtr->xfocus.detail == NotifyNonlinear) { Tcl_DeleteTimerHandler(textPtr->insertBlinkHandler); if (eventPtr->type == FocusIn) { textPtr->flags |= GOT_FOCUS | INSERT_ON; @@ -2380,18 +2377,21 @@ TextEventProc(clientData, eventPtr) textPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; } if (textPtr->inactiveSelBorder != textPtr->selBorder) { - TkTextRedrawTag(NULL, textPtr, NULL, NULL, textPtr->selTagPtr, 1); + TkTextRedrawTag(NULL, textPtr, NULL, NULL, textPtr->selTagPtr, + 1); } TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); TkTextIndexForwChars(NULL, &index, 1, &index2, COUNT_INDICES); - /* - * While we wish to redisplay, no heights have changed, so - * no need to call TkTextInvalidateLineMetrics + + /* + * While we wish to redisplay, no heights have changed, so no need + * to call TkTextInvalidateLineMetrics */ + TkTextChanged(NULL, textPtr, &index, &index2); if (textPtr->highlightWidth > 0) { TkTextRedrawRegion(textPtr, 0, 0, textPtr->highlightWidth, - textPtr->highlightWidth); + textPtr->highlightWidth); } } } @@ -2402,9 +2402,9 @@ TextEventProc(clientData, eventPtr) * * TextCmdDeletedProc -- * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. + * This function is invoked when a widget command is deleted. If the + * widget isn't already in the process of being destroyed, this command + * destroys it. * * Results: * None. @@ -2423,10 +2423,10 @@ TextCmdDeletedProc(clientData) Tk_Window tkwin = textPtr->tkwin; /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which this flag is - * already set) or because the command was deleted, and then this - * procedure destroys the widget. + * This function could be invoked either because the window was destroyed + * and the command was then deleted (in which this flag is already set) or + * because the command was deleted, and then this function destroys the + * widget. */ if (!(textPtr->flags & DESTROYED)) { @@ -2444,18 +2444,18 @@ TextCmdDeletedProc(clientData) * * InsertChars -- * - * This procedure implements most of the functionality of the - * "insert" widget command. + * This function implements most of the functionality of the "insert" + * widget command. * * Results: * The length of the inserted string. * * Side effects: - * The characters in "stringPtr" get added to the text just before - * the character indicated by "indexPtr". - * - * If 'viewUpdate' is true, we may adjust the window - * contents' y-position, and scrollbar setting. + * The characters in "stringPtr" get added to the text just before the + * character indicated by "indexPtr". + * + * If 'viewUpdate' is true, we may adjust the window contents' + * y-position, and scrollbar setting. * *---------------------------------------------------------------------- */ @@ -2464,58 +2464,56 @@ static int InsertChars(sharedTextPtr, textPtr, indexPtr, stringPtr, viewUpdate) TkSharedText *sharedTextPtr; TkText *textPtr; /* Overall information about text widget. */ - TkTextIndex *indexPtr; /* Where to insert new characters. May be - * modified if the index is not valid - * for insertion (e.g. if at "end"). */ + TkTextIndex *indexPtr; /* Where to insert new characters. May be + * modified if the index is not valid for + * insertion (e.g. if at "end"). */ Tcl_Obj *stringPtr; /* Null-terminated string containing new * information to add to text. */ - int viewUpdate; /* Update the view if set */ + int viewUpdate; /* Update the view if set */ { int lineIndex, length; TkText *tPtr; int *lineAndByteIndex; int resetViewCount; int pixels[2*PIXEL_CLIENTS]; - + CONST char *string = Tcl_GetStringFromObj(stringPtr, &length); if (sharedTextPtr == NULL) { sharedTextPtr = textPtr->sharedTextPtr; } - + /* - * Don't allow insertions on the last (dummy) line of the text. - * This is the only place in this function where the indexPtr is - * modified. + * Don't allow insertions on the last (dummy) line of the text. This is + * the only place in this function where the indexPtr is modified. */ lineIndex = TkBTreeLinesTo(textPtr, indexPtr->linePtr); if (lineIndex == TkBTreeNumLines(sharedTextPtr->tree, textPtr)) { lineIndex--; - TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, lineIndex, - 1000000, indexPtr); + TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, lineIndex, 1000000, + indexPtr); } - + /* - * Notify the display module that lines are about to change, then do - * the insertion. If the insertion occurs on the top line of the - * widget (textPtr->topIndex), then we have to recompute topIndex - * after the insertion, since the insertion could invalidate it. + * Notify the display module that lines are about to change, then do the + * insertion. If the insertion occurs on the top line of the widget + * (textPtr->topIndex), then we have to recompute topIndex after the + * insertion, since the insertion could invalidate it. */ resetViewCount = 0; if (sharedTextPtr->refCount > PIXEL_CLIENTS) { - lineAndByteIndex = (int*)ckalloc(sizeof(int)* - 2*sharedTextPtr->refCount); + lineAndByteIndex = (int *) + ckalloc(sizeof(int) * 2 * sharedTextPtr->refCount); } else { lineAndByteIndex = pixels; } - for (tPtr = sharedTextPtr->peers; tPtr != NULL ; - tPtr = tPtr->next) { + for (tPtr = sharedTextPtr->peers; tPtr != NULL ; tPtr = tPtr->next) { lineAndByteIndex[resetViewCount] = -1; if (indexPtr->linePtr == tPtr->topIndex.linePtr) { - lineAndByteIndex[resetViewCount] = - TkBTreeLinesTo(tPtr, indexPtr->linePtr); + lineAndByteIndex[resetViewCount] = + TkBTreeLinesTo(tPtr, indexPtr->linePtr); lineAndByteIndex[resetViewCount+1] = tPtr->topIndex.byteIndex; if (lineAndByteIndex[resetViewCount+1] > indexPtr->byteIndex) { lineAndByteIndex[resetViewCount+1] += length; @@ -2523,11 +2521,11 @@ InsertChars(sharedTextPtr, textPtr, indexPtr, stringPtr, viewUpdate) } resetViewCount += 2; } - + TkTextChanged(sharedTextPtr, NULL, indexPtr, indexPtr); - + sharedTextPtr->stateEpoch++; - + TkBTreeInsertChars(sharedTextPtr->tree, indexPtr, string); /* @@ -2535,33 +2533,31 @@ InsertChars(sharedTextPtr, textPtr, indexPtr, stringPtr, viewUpdate) */ if (sharedTextPtr->undo) { - TkTextIndex toIndex; - - if (sharedTextPtr->autoSeparators && - sharedTextPtr->lastEditMode != TK_TEXT_EDIT_INSERT) { - TkUndoInsertUndoSeparator(sharedTextPtr->undoStack); - } - - sharedTextPtr->lastEditMode = TK_TEXT_EDIT_INSERT; + TkTextIndex toIndex; + + if (sharedTextPtr->autoSeparators && + sharedTextPtr->lastEditMode != TK_TEXT_EDIT_INSERT) { + TkUndoInsertUndoSeparator(sharedTextPtr->undoStack); + } + + sharedTextPtr->lastEditMode = TK_TEXT_EDIT_INSERT; TkTextIndexForwBytes(textPtr, indexPtr, length, &toIndex); TextPushUndoAction(textPtr, stringPtr, 1, indexPtr, &toIndex); } - + UpdateDirtyFlag(sharedTextPtr); resetViewCount = 0; - for (tPtr = sharedTextPtr->peers; tPtr != NULL ; - tPtr = tPtr->next) { + for (tPtr = sharedTextPtr->peers; tPtr != NULL ; tPtr = tPtr->next) { if (lineAndByteIndex[resetViewCount] != -1) { if ((tPtr != textPtr) || viewUpdate) { TkTextIndex newTop; - TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, - lineAndByteIndex[resetViewCount], - 0, &newTop); - TkTextIndexForwBytes(tPtr, &newTop, - lineAndByteIndex[resetViewCount+1], - &newTop); + + TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, + lineAndByteIndex[resetViewCount], 0, &newTop); + TkTextIndexForwBytes(tPtr, &newTop, + lineAndByteIndex[resetViewCount+1], &newTop); TkTextSetYView(tPtr, &newTop, 0); } } @@ -2570,17 +2566,19 @@ InsertChars(sharedTextPtr, textPtr, indexPtr, stringPtr, viewUpdate) if (sharedTextPtr->refCount > PIXEL_CLIENTS) { ckfree((char*)lineAndByteIndex); } - + /* * Invalidate any selection retrievals in progress. */ - for (tPtr = sharedTextPtr->peers; tPtr != NULL ; - tPtr = tPtr->next) { + for (tPtr = sharedTextPtr->peers; tPtr != NULL ; tPtr = tPtr->next) { tPtr->abortSelections = 1; } - - /* For convenience, return the length of the string */ + + /* + * For convenience, return the length of the string. + */ + return length; } @@ -2589,10 +2587,10 @@ InsertChars(sharedTextPtr, textPtr, indexPtr, stringPtr, viewUpdate) * * TextPushUndoAction -- * - * Shared by insert and delete actions. Stores the appropriate - * scripts into our undo stack. We will add a single refCount to - * the 'undoString' object, so, if it previously had a refCount of - * zero, the caller should not free it. + * Shared by insert and delete actions. Stores the appropriate scripts + * into our undo stack. We will add a single refCount to the 'undoString' + * object, so, if it previously had a refCount of zero, the caller should + * not free it. * * Results: * None. @@ -2605,50 +2603,66 @@ InsertChars(sharedTextPtr, textPtr, indexPtr, stringPtr, viewUpdate) static void TextPushUndoAction (textPtr, undoString, insert, index1Ptr, index2Ptr) - TkText *textPtr; /* Overall information about text widget. */ - Tcl_Obj *undoString; /* New text */ - int insert; /* 1 if insert, else delete */ - CONST TkTextIndex *index1Ptr;/* Index describing first location */ - CONST TkTextIndex *index2Ptr;/* Index describing second location */ + TkText *textPtr; /* Overall information about text widget. */ + Tcl_Obj *undoString; /* New text */ + int insert; /* 1 if insert, else delete */ + CONST TkTextIndex *index1Ptr; + /* Index describing first location */ + CONST TkTextIndex *index2Ptr; + /* Index describing second location */ { TkUndoSubAtom *iAtom, *dAtom; - - /* Create the helpers */ + + /* + * Create the helpers. + */ + Tcl_Obj *seeInsertObj = Tcl_NewObj(); Tcl_Obj *markSet1InsertObj = Tcl_NewObj(); Tcl_Obj *markSet2InsertObj = Tcl_NewObj(); Tcl_Obj *insertCmdObj = Tcl_NewObj(); Tcl_Obj *deleteCmdObj = Tcl_NewObj(); - - /* Get the index positions */ + + /* + * Get the index positions. + */ + Tcl_Obj *index1Obj = TkTextNewIndexObj(NULL, index1Ptr); Tcl_Obj *index2Obj = TkTextNewIndexObj(NULL, index2Ptr); - /* These need refCounts, because they are used more than once below */ + /* + * These need refCounts, because they are used more than once below. + */ + Tcl_IncrRefCount(seeInsertObj); Tcl_IncrRefCount(index1Obj); Tcl_IncrRefCount(index2Obj); - Tcl_ListObjAppendElement(NULL, seeInsertObj, - Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1)); - Tcl_ListObjAppendElement(NULL, seeInsertObj, Tcl_NewStringObj("see",3)); - Tcl_ListObjAppendElement(NULL, seeInsertObj, Tcl_NewStringObj("insert",6)); - - Tcl_ListObjAppendElement(NULL, markSet1InsertObj, - Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1)); - Tcl_ListObjAppendElement(NULL, markSet1InsertObj, - Tcl_NewStringObj("mark",4)); - Tcl_ListObjAppendElement(NULL, markSet1InsertObj, - Tcl_NewStringObj("set",3)); - Tcl_ListObjAppendElement(NULL, markSet1InsertObj, - Tcl_NewStringObj("insert",6)); + Tcl_ListObjAppendElement(NULL, seeInsertObj, + Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1)); + Tcl_ListObjAppendElement(NULL, seeInsertObj, Tcl_NewStringObj("see", 3)); + Tcl_ListObjAppendElement(NULL, seeInsertObj, + Tcl_NewStringObj("insert", 6)); + + Tcl_ListObjAppendElement(NULL, markSet1InsertObj, + Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1)); + Tcl_ListObjAppendElement(NULL, markSet1InsertObj, + Tcl_NewStringObj("mark", 4)); + Tcl_ListObjAppendElement(NULL, markSet1InsertObj, + Tcl_NewStringObj("set", 3)); + Tcl_ListObjAppendElement(NULL, markSet1InsertObj, + Tcl_NewStringObj("insert", 6)); markSet2InsertObj = Tcl_DuplicateObj(markSet1InsertObj); Tcl_ListObjAppendElement(NULL, markSet1InsertObj, index1Obj); Tcl_ListObjAppendElement(NULL, markSet2InsertObj, index2Obj); Tcl_ListObjAppendElement(NULL, insertCmdObj, Tcl_NewStringObj("insert",6)); Tcl_ListObjAppendElement(NULL, insertCmdObj, index1Obj); - /* Only use of 'undoString' is here */ + + /* + * Only use of 'undoString' is here. + */ + Tcl_ListObjAppendElement(NULL, insertCmdObj, undoString); Tcl_ListObjAppendElement(NULL, deleteCmdObj, Tcl_NewStringObj("delete",6)); @@ -2657,47 +2671,42 @@ TextPushUndoAction (textPtr, undoString, insert, index1Ptr, index2Ptr) /* * Note: we don't wish to use textPtr->widgetCmd in these callbacks - * because if we delete the textPtr, but peers still exist, we will - * then have references to a non-existent Tcl_Command in the undo - * stack, which will lead to crashes later. Also, the behaviour of - * the widget wrt bindings (%W substitutions) always uses the widget - * path name, so there is no good reason the undo stack should do - * otherwise. - * - * For the 'insert' and 'delete' actions, we have to register a - * functional callback, because these actions are defined to - * operate on the underlying data shared by all peers. + * because if we delete the textPtr, but peers still exist, we will then + * have references to a non-existent Tcl_Command in the undo stack, which + * will lead to crashes later. Also, the behaviour of the widget wrt + * bindings (%W substitutions) always uses the widget path name, so there + * is no good reason the undo stack should do otherwise. + * + * For the 'insert' and 'delete' actions, we have to register a functional + * callback, because these actions are defined to operate on the + * underlying data shared by all peers. */ - iAtom = TkUndoMakeSubAtom(&TextUndoRedoCallback, - (ClientData)textPtr->sharedTextPtr, - insertCmdObj, NULL); + + iAtom = TkUndoMakeSubAtom(&TextUndoRedoCallback, + (ClientData)textPtr->sharedTextPtr, insertCmdObj, NULL); TkUndoMakeCmdSubAtom(NULL, markSet2InsertObj, iAtom); TkUndoMakeCmdSubAtom(NULL, seeInsertObj, iAtom); - - dAtom = TkUndoMakeSubAtom(&TextUndoRedoCallback, - (ClientData)textPtr->sharedTextPtr, - deleteCmdObj, NULL); + + dAtom = TkUndoMakeSubAtom(&TextUndoRedoCallback, + (ClientData)textPtr->sharedTextPtr, deleteCmdObj, NULL); TkUndoMakeCmdSubAtom(NULL, markSet1InsertObj, dAtom); TkUndoMakeCmdSubAtom(NULL, seeInsertObj, dAtom); - + Tcl_DecrRefCount(seeInsertObj); Tcl_DecrRefCount(index1Obj); Tcl_DecrRefCount(index2Obj); - /* - * Depending whether the action is to insert or delete, we provide - * the appropriate second and third arguments to TkUndoPushAction. - * (The first is the 'actionCommand', and the second the - * 'revertCommand'). + /* + * Depending whether the action is to insert or delete, we provide the + * appropriate second and third arguments to TkUndoPushAction. (The first + * is the 'actionCommand', and the second the 'revertCommand'). */ + if (insert) { - TkUndoPushAction(textPtr->sharedTextPtr->undoStack, - iAtom, dAtom); + TkUndoPushAction(textPtr->sharedTextPtr->undoStack, iAtom, dAtom); } else { - TkUndoPushAction(textPtr->sharedTextPtr->undoStack, - dAtom, iAtom); + TkUndoPushAction(textPtr->sharedTextPtr->undoStack, dAtom, iAtom); } - } /* @@ -2705,96 +2714,95 @@ TextPushUndoAction (textPtr, undoString, insert, index1Ptr, index2Ptr) * * TextUndoRedoCallback -- * - * This procedure is registered with the generic undo/redo code - * to handle 'insert' and 'delete' actions on all text widgets. - * We cannot perform those actions on any particular text widget, - * because that text widget might have been deleted by the time - * we get here. + * This function is registered with the generic undo/redo code to handle + * 'insert' and 'delete' actions on all text widgets. We cannot perform + * those actions on any particular text widget, because that text widget + * might have been deleted by the time we get here. * * Results: * A standard Tcl result. * * Side effects: - * Will insert or delete text, depending on the first word - * contained in objPtr. - * + * Will insert or delete text, depending on the first word contained in + * objPtr. + * *---------------------------------------------------------------------- */ int TextUndoRedoCallback(interp, clientData, objPtr) - Tcl_Interp *interp; /* Current interpreter. */ - ClientData clientData; /* Passed from undo code, but - * contains our shared text - * data structure. */ - Tcl_Obj *objPtr; /* Arguments of a command to - * be handled by the shared - * text data structure. */ + Tcl_Interp *interp; /* Current interpreter. */ + ClientData clientData; /* Passed from undo code, but contains our + * shared text data structure. */ + Tcl_Obj *objPtr; /* Arguments of a command to be handled by the + * shared text data structure. */ { TkSharedText *sharedPtr = (TkSharedText*)clientData; int objc; Tcl_Obj **objv; int res; TkText *textPtr; - + res = Tcl_ListObjGetElements(interp, objPtr, &objc, &objv); if (res != TCL_OK) { return res; } - /* - * If possible, use a real text widget to perform the undo/redo - * action (i.e. insertion or deletion of text). This provides - * maximum compatibility with older versions of Tk, in which the - * user may rename the text widget to allow capture of undo or - * redo actions. - * - * In particular, this sorting of capture is useful in text editors - * based on the Tk text widget, which need to know which new text - * needs re-coloring. - * - * It would be better if the text widget provided some other - * mechanism to allow capture of this information ("What has - * just changed in the text widget?"). What we have here is - * not entirely satisfactory under all circumstances. + /* + * If possible, use a real text widget to perform the undo/redo action + * (i.e. insertion or deletion of text). This provides maximum + * compatibility with older versions of Tk, in which the user may rename + * the text widget to allow capture of undo or redo actions. + * + * In particular, this sorting of capture is useful in text editors based + * on the Tk text widget, which need to know which new text needs + * re-coloring. + * + * It would be better if the text widget provided some other mechanism to + * allow capture of this information ("What has just changed in the text + * widget?"). What we have here is not entirely satisfactory under all + * circumstances. */ + textPtr = sharedPtr->peers; while (textPtr != NULL) { - if (textPtr->start == NULL && textPtr->end == NULL) { + if (textPtr->start == NULL && textPtr->end == NULL) { Tcl_Obj *cmdNameObj, *evalObj; - + evalObj = Tcl_NewObj(); Tcl_IncrRefCount(evalObj); + /* - * We might wish to use the real, current command-name - * for the widget, but this will break any code that has - * over-ridden the widget, and is expecting to observe - * the insert/delete actions which are caused by undo/redo - * operations. - * + * We might wish to use the real, current command-name for the + * widget, but this will break any code that has over-ridden the + * widget, and is expecting to observe the insert/delete actions + * which are caused by undo/redo operations. + * * cmdNameObj = Tcl_NewObj(); - * Tcl_GetCommandFullName(interp, textPtr->widgetCmd, - * cmdNameObj); - * + * Tcl_GetCommandFullName(interp, textPtr->widgetCmd, cmdNameObj); + * * While such interception is not explicitly documented as - * supported, it does occur, and so until we can provide - * some alternative mechanism for such code to do what - * it needs, we allow it to take place here. + * supported, it does occur, and so until we can provide some + * alternative mechanism for such code to do what it needs, we + * allow it to take place here. */ + cmdNameObj = Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1); Tcl_ListObjAppendElement(NULL, evalObj, cmdNameObj); Tcl_ListObjAppendList(NULL, evalObj, objPtr); res = Tcl_EvalObjEx(interp, evalObj, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(evalObj); - return res; - } - textPtr = textPtr->next; + return res; + } + textPtr = textPtr->next; } + /* - * If there's no current text widget which shows everything, then - * we fall back on acting directly. This means there is no way to - * intercept from the Tcl level. + * If there's no current text widget which shows everything, then we fall + * back on acting directly. This means there is no way to intercept from + * the Tcl level. */ + return SharedTextObjCmd((ClientData)sharedPtr, interp, objc+1, objv-1); } @@ -2803,12 +2811,12 @@ TextUndoRedoCallback(interp, clientData, objPtr) * * CountIndices -- * - * This procedure implements most of the functionality of the - * "count" widget command. + * This function implements most of the functionality of the "count" + * widget command. * * Note that 'textPtr' is only used if we need to check for elided * attributes, i.e. if type is COUNT_DISPLAY_INDICES or - * COUNT_DISPLAY_CHARS. + * COUNT_DISPLAY_CHARS * * Results: * Returns the number of characters in the range. @@ -2821,23 +2829,24 @@ TextUndoRedoCallback(interp, clientData, objPtr) static int CountIndices(textPtr, indexPtr1, indexPtr2, type) - CONST TkText *textPtr; /* Overall information about text widget. */ - CONST TkTextIndex *indexPtr1;/* Index describing location of first - * character to delete. */ - CONST TkTextIndex *indexPtr2;/* Index describing location of last - * character to delete. NULL means just - * delete the one character given by - * indexPtr1. */ - TkTextCountType type; /* The kind of indices to count */ + CONST TkText *textPtr; /* Overall information about text widget. */ + CONST TkTextIndex *indexPtr1; + /* Index describing location of first + * character to delete. */ + CONST TkTextIndex *indexPtr2; + /* Index describing location of last character + * to delete. NULL means just delete the one + * character given by indexPtr1. */ + TkTextCountType type; /* The kind of indices to count */ { /* * Order the starting and stopping indices. */ int compare = TkTextIndexCmp(indexPtr1, indexPtr2); - + if (compare == 0) { - return 0; + return 0; } else if (compare > 0) { return -TkTextIndexCount(textPtr, indexPtr2, indexPtr1, type); } else { @@ -2850,39 +2859,40 @@ CountIndices(textPtr, indexPtr1, indexPtr2, type) * * DeleteChars -- * - * This procedure implements most of the functionality of the - * "delete" widget command. + * This function implements most of the functionality of the "delete" + * widget command. * * Results: * Returns a standard Tcl result, currently always TCL_OK. * * Side effects: * Characters get deleted from the text. - * - * If 'viewUpdate' is true, we may adjust the window - * contents' y-position, and scrollbar setting. - * - * If 'viewUpdate' is false, true we can guarantee that - * textPtr->topIndex points to a valid TkTextLine after this - * procedure returns. However, if 'viewUpdate' is false, then - * there is no such guarantee (topIndex.linePtr can be garbage). - * The caller is expected to take actions to ensure the topIndex - * is validated before laying out the window again. + * + * If 'viewUpdate' is true, we may adjust the window contents' + * y-position, and scrollbar setting. + * + * If 'viewUpdate' is false, true we can guarantee that textPtr->topIndex + * points to a valid TkTextLine after this function returns. However, if + * 'viewUpdate' is false, then there is no such guarantee (since + * topIndex.linePtr can be garbage). The caller is expected to take + * actions to ensure the topIndex is validated before laying out the + * window again. * *---------------------------------------------------------------------- */ static int DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) - TkSharedText *sharedTextPtr; /* Shared portion of peer widgets. */ - TkText *textPtr; /* Overall information about text widget. */ - CONST TkTextIndex *indexPtr1;/* Index describing location of first - * character to delete. */ - CONST TkTextIndex *indexPtr2;/* Index describing location of last - * character to delete. NULL means just - * delete the one character given by - * indexPtr1. */ - int viewUpdate; /* Update vertical view if set. */ + TkSharedText *sharedTextPtr;/* Shared portion of peer widgets. */ + TkText *textPtr; /* Overall information about text widget. */ + CONST TkTextIndex *indexPtr1; + /* Index describing location of first + * character to delete. */ + CONST TkTextIndex *indexPtr2; + /* Index describing location of last character + * to delete. NULL means just delete the one + * character given by indexPtr1. */ + int viewUpdate; /* Update vertical view if set. */ { int line1, line2; TkTextIndex index1, index2; @@ -2894,7 +2904,7 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) if (sharedTextPtr == NULL) { sharedTextPtr = textPtr->sharedTextPtr; } - + /* * Prepare the starting and stopping indices. */ @@ -2916,15 +2926,15 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) } /* - * The code below is ugly, but it's needed to make sure there - * is always a dummy empty line at the end of the text. If the - * final newline of the file (just before the dummy line) is being - * deleted, then back up index to just before the newline. If - * there is a newline just before the first character being deleted, - * then back up the first index too, so that an even number of lines - * gets deleted. Furthermore, remove any tags that are present on - * the newline that isn't going to be deleted after all (this simulates - * deleting the newline and then adding a "clean" one back again). + * The code below is ugly, but it's needed to make sure there is always a + * dummy empty line at the end of the text. If the final newline of the + * file (just before the dummy line) is being deleted, then back up index + * to just before the newline. If there is a newline just before the first + * character being deleted, then back up the first index too, so that an + * even number of lines gets deleted. Furthermore, remove any tags that + * are present on the newline that isn't going to be deleted after all + * (this simulates deleting the newline and then adding a "clean" one back + * again). */ line1 = TkBTreeLinesTo(textPtr, index1.linePtr); @@ -2952,71 +2962,69 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) if (line1 < line2) { /* - * We are deleting more than one line. For speed, - * we remove all tags from the range first. If we - * don't do this, the code below can (when there are - * many tags) grow non-linearly in execution time. + * We are deleting more than one line. For speed, we remove all tags + * from the range first. If we don't do this, the code below can (when + * there are many tags) grow non-linearly in execution time. */ + Tcl_HashSearch search; Tcl_HashEntry *hPtr; int i; - - for (i = 0, hPtr = Tcl_FirstHashEntry(&sharedTextPtr->tagTable, - &search); + + for (i=0, hPtr=Tcl_FirstHashEntry(&sharedTextPtr->tagTable, &search); hPtr != NULL; i++, hPtr = Tcl_NextHashEntry(&search)) { - TkTextTag *tagPtr; - tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); + TkTextTag *tagPtr = (TkTextTag *) Tcl_GetHashValue(hPtr); + TkBTreeTag(&index1, &index2, tagPtr, 0); } + /* - * Special case for the sel tag which is not in the hash table. - * We need to do this once for each peer text widget. + * Special case for the sel tag which is not in the hash table. We + * need to do this once for each peer text widget. */ - - for (tPtr = sharedTextPtr->peers; tPtr != NULL ; - tPtr = tPtr->next) { + + for (tPtr = sharedTextPtr->peers; tPtr != NULL ; + tPtr = tPtr->next) { if (TkBTreeTag(&index1, &index2, tPtr->selTagPtr, 0)) { /* - * Send an event that the selection changed. - * This is equivalent to - * "event generate $textWidget <<Selection>>" + * Send an event that the selection changed. This is + * equivalent to: + * event generate $textWidget <<Selection>> */ TkTextSelectionEvent(textPtr); - tPtr->abortSelections = 1; } } } - + /* - * Tell the display what's about to happen so it can discard - * obsolete display information, then do the deletion. Also, - * if the deletion involves the top line on the screen, then - * we have to reset the view (the deletion will invalidate - * textPtr->topIndex). Compute what the new first character - * will be, then do the deletion, then reset the view. + * Tell the display what's about to happen so it can discard obsolete + * display information, then do the deletion. Also, if the deletion + * involves the top line on the screen, then we have to reset the view + * (the deletion will invalidate textPtr->topIndex). Compute what the new + * first character will be, then do the deletion, then reset the view. */ TkTextChanged(sharedTextPtr, NULL, &index1, &index2); - + resetViewCount = 0; if (sharedTextPtr->refCount > PIXEL_CLIENTS) { - lineAndByteIndex = (int*)ckalloc(sizeof(int)* - 2*sharedTextPtr->refCount); + lineAndByteIndex = (int *) + ckalloc(sizeof(int) * 2 * sharedTextPtr->refCount); } else { lineAndByteIndex = pixels; } - for (tPtr = sharedTextPtr->peers; tPtr != NULL ; - tPtr = tPtr->next) { + for (tPtr = sharedTextPtr->peers; tPtr != NULL ; tPtr = tPtr->next) { int line = 0; int byteIndex = 0; int resetView = 0; + if (TkTextIndexCmp(&index2, &tPtr->topIndex) >= 0) { if (TkTextIndexCmp(&index1, &tPtr->topIndex) <= 0) { /* - * Deletion range straddles topIndex: use the beginning - * of the range as the new topIndex. + * Deletion range straddles topIndex: use the beginning of the + * range as the new topIndex. */ resetView = 1; @@ -3024,8 +3032,8 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) byteIndex = index1.byteIndex; } else if (index1.linePtr == tPtr->topIndex.linePtr) { /* - * Deletion range starts on top line but after topIndex. - * Use the current topIndex as the new one. + * Deletion range starts on top line but after topIndex. Use + * the current topIndex as the new one. */ resetView = 1; @@ -3034,9 +3042,9 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) } } else if (index2.linePtr == tPtr->topIndex.linePtr) { /* - * Deletion range ends on top line but before topIndex. - * Figure out what will be the new character index for - * the character currently pointed to by topIndex. + * Deletion range ends on top line but before topIndex. Figure out + * what will be the new character index for the character + * currently pointed to by topIndex. */ resetView = 1; @@ -3056,17 +3064,17 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) } resetViewCount+=2; } - + /* * Push the deletion on the undo stack */ if (sharedTextPtr->undo) { Tcl_Obj *get; - + if (sharedTextPtr->autoSeparators && (sharedTextPtr->lastEditMode != TK_TEXT_EDIT_DELETE)) { - TkUndoInsertUndoSeparator(sharedTextPtr->undoStack); + TkUndoInsertUndoSeparator(sharedTextPtr->undoStack); } sharedTextPtr->lastEditMode = TK_TEXT_EDIT_DELETE; @@ -3081,20 +3089,21 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) TkBTreeDeleteChars(sharedTextPtr->tree, &index1, &index2); resetViewCount = 0; - for (tPtr = sharedTextPtr->peers; tPtr != NULL ; - tPtr = tPtr->next) { + for (tPtr = sharedTextPtr->peers; tPtr != NULL ; tPtr = tPtr->next) { int line = lineAndByteIndex[resetViewCount]; + if (line != -1) { int byteIndex = lineAndByteIndex[resetViewCount+1]; + if (tPtr == textPtr) { if (viewUpdate) { - TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, - line, byteIndex, &index1); + TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, line, + byteIndex, &index1); TkTextSetYView(tPtr, &index1, 0); } } else { - TkTextMakeByteIndex(sharedTextPtr->tree, NULL, - line, byteIndex, &index1); + TkTextMakeByteIndex(sharedTextPtr->tree, NULL, line, byteIndex, + &index1); TkTextSetYView(tPtr, &index1, 0); } } @@ -3103,20 +3112,19 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) if (sharedTextPtr->refCount > PIXEL_CLIENTS) { ckfree((char*)lineAndByteIndex); } - + if (line1 >= line2) { - + /* - * Invalidate any selection retrievals in progress, assuming - * we didn't check for this case above. + * Invalidate any selection retrievals in progress, assuming we didn't + * check for this case above. */ - for (tPtr = sharedTextPtr->peers; tPtr != NULL ; - tPtr = tPtr->next) { + for (tPtr = sharedTextPtr->peers; tPtr != NULL ; tPtr = tPtr->next) { tPtr->abortSelections = 1; } } - + return TCL_OK; } @@ -3125,15 +3133,15 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) * * TextFetchSelection -- * - * This procedure is called back by Tk when the selection is - * requested by someone. It returns part or all of the selection - * in a buffer provided by the caller. + * This function is called back by Tk when the selection is requested by + * someone. It returns part or all of the selection in a buffer provided + * by the caller. * * Results: - * The return value is the number of non-NULL bytes stored - * at buffer. Buffer is filled (or partially filled) with a - * NULL-terminated string containing part or all of the selection, - * as given by offset and maxBytes. + * The return value is the number of non-NULL bytes stored at buffer. + * Buffer is filled (or partially filled) with a NULL-terminated string + * containing part or all of the selection, as given by offset and + * maxBytes. * * Side effects: * None. @@ -3143,14 +3151,13 @@ DeleteChars(sharedTextPtr, textPtr, indexPtr1, indexPtr2, viewUpdate) static int TextFetchSelection(clientData, offset, buffer, maxBytes) - ClientData clientData; /* Information about text widget. */ - int offset; /* Offset within selection of first - * character to be returned. */ - char *buffer; /* Location in which to place - * selection. */ - int maxBytes; /* Maximum number of bytes to place - * at buffer, not including terminating - * NULL character. */ + ClientData clientData; /* Information about text widget. */ + int offset; /* Offset within selection of first character + * to be returned. */ + char *buffer; /* Location in which to place selection. */ + int maxBytes; /* Maximum number of bytes to place at buffer, + * not including terminating NULL + * character. */ { register TkText *textPtr = (TkText *) clientData; TkTextIndex eof; @@ -3163,23 +3170,21 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) } /* - * Find the beginning of the next range of selected text. Note: if - * the selection is being retrieved in multiple pieces (offset != 0) - * and some modification has been made to the text that affects the - * selection then reject the selection request (make 'em start over - * again). + * Find the beginning of the next range of selected text. Note: if the + * selection is being retrieved in multiple pieces (offset != 0) and some + * modification has been made to the text that affects the selection then + * reject the selection request (make 'em start over again). */ if (offset == 0) { - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - 0, 0, &textPtr->selIndex); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0, + &textPtr->selIndex); textPtr->abortSelections = 0; } else if (textPtr->abortSelections) { return 0; } - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), - 0, &eof); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), 0, &eof); TkBTreeStartSearch(&textPtr->selIndex, &eof, textPtr->selTagPtr, &search); if (!TkBTreeCharTagged(&textPtr->selIndex, textPtr->selTagPtr)) { if (!TkBTreeNextTag(&search)) { @@ -3194,8 +3199,8 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) /* * Each iteration through the outer loop below scans one selected range. - * Each iteration through the inner loop scans one segment in the - * selected range. + * Each iteration through the inner loop scans one segment in the selected + * range. */ count = 0; @@ -3209,9 +3214,9 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) } /* - * Copy information from character segments into the buffer - * until either we run out of space in the buffer or we get - * to the end of this range of text. + * Copy information from character segments into the buffer until + * either we run out of space in the buffer or we get to the end of + * this range of text. */ while (1) { @@ -3257,7 +3262,7 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) textPtr->selIndex = search.curIndex; } - fetchDone: + fetchDone: *buffer = 0; return count; } @@ -3267,11 +3272,10 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) * * TkTextLostSelection -- * - * This procedure is called back by Tk when the selection is - * grabbed away from a text widget. On Windows and Mac systems, we - * want to remember the selection for the next time the focus - * enters the window. On Unix, just remove the "sel" tag from - * everything in the widget. + * This function is called back by Tk when the selection is grabbed away + * from a text widget. On Windows and Mac systems, we want to remember + * the selection for the next time the focus enters the window. On Unix, + * just remove the "sel" tag from everything in the widget. * * Results: * None. @@ -3284,7 +3288,7 @@ TextFetchSelection(clientData, offset, buffer, maxBytes) void TkTextLostSelection(clientData) - ClientData clientData; /* Information about text widget. */ + ClientData clientData; /* Information about text widget. */ { register TkText *textPtr = (TkText *) clientData; #ifdef ALWAYS_SHOW_SELECTION @@ -3295,23 +3299,23 @@ TkTextLostSelection(clientData) } /* - * On Windows and Mac systems, we want to remember the selection - * for the next time the focus enters the window. On Unix, - * just remove the "sel" tag from everything in the widget. + * On Windows and Mac systems, we want to remember the selection for the + * next time the focus enters the window. On Unix, just remove the "sel" + * tag from everything in the widget. */ TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0, &start); - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), - 0, &end); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), 0, &end); TkTextRedrawTag(NULL, textPtr, &start, &end, textPtr->selTagPtr, 1); TkBTreeTag(&start, &end, textPtr->selTagPtr, 0); #endif - + /* - * Send an event that the selection changed. This is equivalent to - * "event generate $textWidget <<Selection>>" + * Send an event that the selection changed. This is equivalent to: + * event generate $textWidget <<Selection>> */ + TkTextSelectionEvent(textPtr); textPtr->flags &= ~GOT_SELECTION; @@ -3322,8 +3326,8 @@ TkTextLostSelection(clientData) * * TkTextSelectionEvent -- * - * When anything relevant to the "sel" tag has been changed, - * call this procedure to generate a <<Selection>> event. + * When anything relevant to the "sel" tag has been changed, call this + * function to generate a <<Selection>> event. * * Results: * None. @@ -3334,15 +3338,17 @@ TkTextLostSelection(clientData) *---------------------------------------------------------------------- */ -void -TkTextSelectionEvent(textPtr) +void +TkTextSelectionEvent(textPtr) TkText *textPtr; { /* - * Send an event that the selection changed. This is equivalent to - * "event generate $textWidget <<Selection>>" + * Send an event that the selection changed. This is equivalent to: + * event generate $textWidget <<Selection>> */ + XEvent event; + memset((VOID *) &event, 0, sizeof(event)); event.xany.type = VirtualEvent; event.xany.serial = NextRequest(Tk_Display(textPtr->tkwin)); @@ -3358,15 +3364,15 @@ TkTextSelectionEvent(textPtr) * * TextBlinkProc -- * - * This procedure is called as a timer handler to blink the - * insertion cursor off and on. + * This function is called as a timer handler to blink the insertion + * cursor off and on. * * Results: * None. * * Side effects: - * The cursor gets turned on or off, redisplay gets invoked, - * and this procedure reschedules itself. + * The cursor gets turned on or off, redisplay gets invoked, and this + * function reschedules itself. * *---------------------------------------------------------------------- */ @@ -3383,10 +3389,10 @@ TextBlinkProc(clientData) !(textPtr->flags & GOT_FOCUS) || (textPtr->insertOffTime == 0)) { if ((textPtr->insertOffTime == 0) && !(textPtr->flags & INSERT_ON)) { /* - * The widget was configured to have zero offtime while - * the insertion point was not displayed. We have to - * display it once. + * The widget was configured to have zero offtime while the + * insertion point was not displayed. We have to display it once. */ + textPtr->flags |= INSERT_ON; goto redrawInsert; } @@ -3407,12 +3413,12 @@ TextBlinkProc(clientData) if (textPtr->insertCursorType) { /* Block cursor */ TkTextRedrawRegion(textPtr, x - textPtr->width / 2, y, - charWidth + textPtr->insertWidth / 2, h); + charWidth + textPtr->insertWidth / 2, h); } else { /* I-beam cursor */ TkTextRedrawRegion(textPtr, x - textPtr->insertWidth / 2, y, - textPtr->insertWidth, h); - } + textPtr->insertWidth, h); + } } } @@ -3421,8 +3427,8 @@ TextBlinkProc(clientData) * * TextInsertCmd -- * - * This procedure is invoked to process the "insert" and "replace" - * widget commands for text widgets. + * This function is invoked to process the "insert" and "replace" widget + * commands for text widgets. * * Results: * A standard Tcl result. @@ -3430,21 +3436,21 @@ TextBlinkProc(clientData) * Side effects: * See the user documentation. * - * If 'viewUpdate' is true, we may adjust the window - * contents' y-position, and scrollbar setting. - * + * If 'viewUpdate' is true, we may adjust the window contents' + * y-position, and scrollbar setting. + * *---------------------------------------------------------------------- */ static int TextInsertCmd(sharedTextPtr, textPtr, interp, objc, objv, indexPtr, viewUpdate) - TkSharedText *sharedTextPtr; /* Shared portion of peer widgets. */ - TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ - int objc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects. */ - CONST TkTextIndex *indexPtr; /* Index at which to insert */ - int viewUpdate; /* Update the view if set */ + TkSharedText *sharedTextPtr;/* Shared portion of peer widgets. */ + TkText *textPtr; /* Information about text widget. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ + CONST TkTextIndex *indexPtr;/* Index at which to insert */ + int viewUpdate; /* Update the view if set */ { TkTextIndex index1, index2; int j; @@ -3452,44 +3458,45 @@ TextInsertCmd(sharedTextPtr, textPtr, interp, objc, objv, indexPtr, viewUpdate) if (sharedTextPtr == NULL) { sharedTextPtr = textPtr->sharedTextPtr; } - + index1 = *indexPtr; - for (j = 0; j < objc; j += 2) { + for (j = 0; j < objc; j += 2) { /* - * Here we rely on this call to modify index1 if - * it is outside the acceptable range. In particular, - * if index1 is "end", it must be set to the last - * allowable index for insertion, otherwise - * subsequent tag insertions will fail. + * Here we rely on this call to modify index1 if it is outside the + * acceptable range. In particular, if index1 is "end", it must be set + * to the last allowable index for insertion, otherwise subsequent tag + * insertions will fail. */ - int length = InsertChars(sharedTextPtr, textPtr, &index1, - objv[j], viewUpdate); + + int length = InsertChars(sharedTextPtr, textPtr, &index1, objv[j], + viewUpdate); + if (objc > (j+1)) { Tcl_Obj **tagNamePtrs; TkTextTag **oldTagArrayPtr; int numTags; - + TkTextIndexForwBytes(textPtr, &index1, length, &index2); oldTagArrayPtr = TkBTreeGetTags(&index1, NULL, &numTags); if (oldTagArrayPtr != NULL) { int i; + for (i = 0; i < numTags; i++) { - TkBTreeTag(&index1, &index2, - oldTagArrayPtr[i], 0); + TkBTreeTag(&index1, &index2, oldTagArrayPtr[i], 0); } ckfree((char *) oldTagArrayPtr); } - if (Tcl_ListObjGetElements(interp, objv[j+1], - &numTags, &tagNamePtrs) - != TCL_OK) { + if (Tcl_ListObjGetElements(interp, objv[j+1], &numTags, + &tagNamePtrs) != TCL_OK) { return TCL_ERROR; } else { int i; - + for (i = 0; i < numTags; i++) { CONST char *strTag = Tcl_GetString(tagNamePtrs[i]); - TkBTreeTag(&index1, &index2, - TkTextCreateTag(textPtr, strTag, NULL), 1); + + TkBTreeTag(&index1, &index2, + TkTextCreateTag(textPtr, strTag, NULL), 1); } index1 = index2; } @@ -3503,9 +3510,8 @@ TextInsertCmd(sharedTextPtr, textPtr, interp, objc, objv, indexPtr, viewUpdate) * * TextSearchCmd -- * - * This procedure is invoked to process the "search" widget command - * for text widgets. See the user documentation for details on what - * it does. + * This function is invoked to process the "search" widget command for + * text widgets. See the user documentation for details on what it does. * * Results: * A standard Tcl result. @@ -3528,7 +3534,7 @@ TextSearchCmd(textPtr, interp, objc, objv) static CONST char *switchStrings[] = { "--", "-all", "-backwards", "-count", "-elide", "-exact", - "-forwards", "-hidden", "-nocase", "-nolinestop", + "-forwards", "-hidden", "-nocase", "-nolinestop", "-overlap", "-regexp", "-strictlimits", NULL }; enum SearchSwitches { @@ -3538,10 +3544,11 @@ TextSearchCmd(textPtr, interp, objc, objv) SEARCH_STRICTLIMITS }; - /* - * Set up the search specification, including - * the last 4 fields which are text widget specific + /* + * Set up the search specification, including the last 4 fields which are + * text widget specific. */ + searchSpec.exact = 1; searchSpec.noCase = 0; searchSpec.all = 0; @@ -3553,12 +3560,13 @@ TextSearchCmd(textPtr, interp, objc, objv) searchSpec.noLineStop = 0; searchSpec.overlap = 0; searchSpec.strictLimits = 0; - searchSpec.numLines = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr); + searchSpec.numLines = + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr); searchSpec.clientData = (ClientData)textPtr; searchSpec.addLineProc = &TextSearchAddNextLine; searchSpec.foundMatchProc = &TextSearchFoundMatch; searchSpec.lineIndexProc = &TextSearchGetLineIndex; - + /* * Parse switches and other arguments. */ @@ -3574,6 +3582,7 @@ TextSearchCmd(textPtr, interp, objc, objv) /* * Hide the -hidden option */ + Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad switch \"", Tcl_GetString(objv[i]), "\": must be --, -all, -backward, -count, -elide, ", @@ -3600,10 +3609,12 @@ TextSearchCmd(textPtr, interp, objc, objv) return TCL_ERROR; } i++; - /* - * Assumption objv[i] isn't going to disappear on us during - * this procedure, which is fair. + + /* + * Assumption objv[i] isn't going to disappear on us during this + * function, which is fair. */ + searchSpec.varPtr = objv[i]; break; case SEARCH_ELIDE: @@ -3657,13 +3668,12 @@ TextSearchCmd(textPtr, interp, objc, objv) } /* - * Scan through all of the lines of the text circularly, starting - * at the given index. 'objv[i]' is the pattern which may be an - * exact string or a regexp pattern depending on the flags set - * above. + * Scan through all of the lines of the text circularly, starting at the + * given index. 'objv[i]' is the pattern which may be an exact string or a + * regexp pattern depending on the flags set above. */ - code = SearchPerform(interp, &searchSpec, objv[i], objv[i+1], + code = SearchPerform(interp, &searchSpec, objv[i], objv[i+1], (argsLeft == 1 ? objv[i+2] : NULL)); if (code != TCL_OK) { goto cleanup; @@ -3672,9 +3682,10 @@ TextSearchCmd(textPtr, interp, objc, objv) /* * Set the '-count' variable, if given. */ + if (searchSpec.varPtr != NULL && searchSpec.countPtr != NULL) { Tcl_IncrRefCount(searchSpec.countPtr); - if (Tcl_ObjSetVar2(interp, searchSpec.varPtr, NULL, + if (Tcl_ObjSetVar2(interp, searchSpec.varPtr, NULL, searchSpec.countPtr, TCL_LEAVE_ERR_MSG) == NULL) { code = TCL_ERROR; goto cleanup; @@ -3684,12 +3695,13 @@ TextSearchCmd(textPtr, interp, objc, objv) /* * Set the result */ + if (searchSpec.resPtr != NULL) { Tcl_SetObjResult(interp, searchSpec.resPtr); searchSpec.resPtr = NULL; } - cleanup: + cleanup: if (searchSpec.countPtr != NULL) { Tcl_DecrRefCount(searchSpec.countPtr); } @@ -3705,20 +3717,19 @@ TextSearchCmd(textPtr, interp, objc, objv) * TextSearchGetLineIndex -- * * Extract a row, text offset index position from an objPtr - * - * This means we ignore any embedded windows/images and - * elidden text (unless we are searching that). + * + * This means we ignore any embedded windows/images and elidden text + * (unless we are searching that). * * Results: - * Standard Tcl error code (with a message in the interpreter - * on error conditions). - * + * Standard Tcl error code (with a message in the interpreter on error + * conditions). + * * The offset placed in offsetPosPtr is a utf-8 char* byte index for - * exact searches, and a Unicode character index for regexp - * searches. - * - * The line number should start at zero (searches which wrap - * around assume the first line is numbered 0). + * exact searches, and a Unicode character index for regexp searches. + * + * The line number should start at zero (searches which wrap around + * assume the first line is numbered 0). * * Side effects: * None. @@ -3727,43 +3738,44 @@ TextSearchCmd(textPtr, interp, objc, objv) */ static int TextSearchGetLineIndex(interp, objPtr, searchSpecPtr, linePosPtr, offsetPosPtr) - Tcl_Interp *interp; /* For error messages */ - Tcl_Obj *objPtr; /* Contains a textual index - * like "1.2" */ - SearchSpec *searchSpecPtr; /* Contains other search - * parameters */ - int *linePosPtr; /* For returning the line number */ - int *offsetPosPtr; /* For returning the text offset in - * the line */ + Tcl_Interp *interp; /* For error messages */ + Tcl_Obj *objPtr; /* Contains a textual index like "1.2" */ + SearchSpec *searchSpecPtr; /* Contains other search parameters */ + int *linePosPtr; /* For returning the line number. */ + int *offsetPosPtr; /* For returning the text offset in the + * line. */ { CONST TkTextIndex *indexPtr; int line; TkText *textPtr = (TkText*)(searchSpecPtr->clientData); - + indexPtr = TkTextGetIndexFromObj(interp, textPtr, objPtr); if (indexPtr == NULL) { return TCL_ERROR; } - + line = TkBTreeLinesTo(textPtr, indexPtr->linePtr); if (line >= searchSpecPtr->numLines) { TkTextLine *linePtr; int count = 0; TkTextSegment *segPtr; - + line = searchSpecPtr->numLines-1; linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr, line); - /* Count the number of bytes in this line */ - for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { + + /* + * Count the number of bytes in this line. + */ + + for (segPtr=linePtr->segPtr ; segPtr!=NULL ; segPtr=segPtr->nextPtr) { count += segPtr->size; } - *offsetPosPtr = TextSearchIndexInLine(searchSpecPtr, linePtr, - count); + *offsetPosPtr = TextSearchIndexInLine(searchSpecPtr, linePtr, count); } else { - *offsetPosPtr = TextSearchIndexInLine(searchSpecPtr, - indexPtr->linePtr, indexPtr->byteIndex); + *offsetPosPtr = TextSearchIndexInLine(searchSpecPtr, indexPtr->linePtr, + indexPtr->byteIndex); } - + *linePosPtr = line; return TCL_OK; @@ -3774,15 +3786,15 @@ TextSearchGetLineIndex(interp, objPtr, searchSpecPtr, linePosPtr, offsetPosPtr) * * TextSearchIndexInLine -- * - * Find textual index of 'byteIndex' in the searchable - * characters of 'linePtr'. - * - * This means we ignore any embedded windows/images and - * elidden text (unless we are searching that). + * Find textual index of 'byteIndex' in the searchable characters of + * 'linePtr'. + * + * This means we ignore any embedded windows/images and elidden text + * (unless we are searching that). * * Results: - * The returned index is a utf-8 char* byte index for exact - * searches, and a Unicode character index for regexp searches. + * The returned index is a utf-8 char* byte index for exact searches, and + * a Unicode character index for regexp searches. * * Side effects: * None. @@ -3792,9 +3804,10 @@ TextSearchGetLineIndex(interp, objPtr, searchSpecPtr, linePosPtr, offsetPosPtr) static int TextSearchIndexInLine(searchSpecPtr, linePtr, byteIndex) - CONST SearchSpec *searchSpecPtr; /* Search parameters */ - TkTextLine *linePtr; /* The line we're looking at */ - int byteIndex; /* Index into the line */ + CONST SearchSpec *searchSpecPtr; + /* Search parameters */ + TkTextLine *linePtr; /* The line we're looking at */ + int byteIndex; /* Index into the line */ { TkTextSegment *segPtr; TkTextIndex curIndex; @@ -3805,23 +3818,21 @@ TextSearchIndexInLine(searchSpecPtr, linePtr, byteIndex) curIndex.tree = textPtr->sharedTextPtr->tree; curIndex.linePtr = linePtr; curIndex.byteIndex = 0; for (segPtr = linePtr->segPtr, leftToScan = byteIndex; - leftToScan > 0; - curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { - if ((segPtr->typePtr == &tkTextCharType) - && (searchSpecPtr->searchElide || - !TkTextIsElided(textPtr, &curIndex, NULL))) { + leftToScan > 0; + curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { + if ((segPtr->typePtr == &tkTextCharType) && + (searchSpecPtr->searchElide + || !TkTextIsElided(textPtr, &curIndex, NULL))) { if (leftToScan < segPtr->size) { if (searchSpecPtr->exact) { index += leftToScan; } else { index += Tcl_NumUtfChars(segPtr->body.chars, leftToScan); } + } else if (searchSpecPtr->exact) { + index += segPtr->size; } else { - if (searchSpecPtr->exact) { - index += segPtr->size; - } else { - index += Tcl_NumUtfChars(segPtr->body.chars, -1); - } + index += Tcl_NumUtfChars(segPtr->body.chars, -1); } } leftToScan -= segPtr->size; @@ -3837,18 +3848,18 @@ TextSearchIndexInLine(searchSpecPtr, linePtr, byteIndex) * Adds a line from the text widget to the object 'theLine'. * * Results: - * A pointer to the TkTextLine corresponding to the given line, - * or NULL if there was no available line. - * + * A pointer to the TkTextLine corresponding to the given line, or NULL + * if there was no available line. + * * Also 'lenPtr' (if non-NULL) is filled in with the total length of - * 'theLine' (not just what we added to it, but the length including - * what was already in there). This is in bytes for an exact search - * and in chars for a regexp search. - * - * Also 'extraLinesPtr' (if non-NULL) will have its value - * incremented by 1 for each additional logical line we have - * added because a newline is elided (this will only ever happen - * if we have chosen not to search elided text, of course). + * 'theLine' (not just what we added to it, but the length including what + * was already in there). This is in bytes for an exact search and in + * chars for a regexp search. + * + * Also 'extraLinesPtr' (if non-NULL) will have its value incremented by + * 1 for each additional logical line we have added because a newline is + * elided (this will only ever happen if we have chosen not to search + * elided text, of course). * * Side effects: * Memory may be allocated or re-allocated for theLine's string @@ -3857,26 +3868,25 @@ TextSearchIndexInLine(searchSpecPtr, linePtr, byteIndex) *---------------------------------------------------------------------- */ -static ClientData +static ClientData TextSearchAddNextLine(lineNum, searchSpecPtr, theLine, lenPtr, extraLinesPtr) - int lineNum; /* Line we must add */ - SearchSpec *searchSpecPtr; /* Search parameters */ - Tcl_Obj *theLine; /* Object to append to */ - int *lenPtr; /* For returning the total length */ - int *extraLinesPtr; /* If non-NULL, will have its value - * incremented by the number of - * additional logical lines which are - * merged into this one by newlines - * being elided */ + int lineNum; /* Line we must add */ + SearchSpec *searchSpecPtr; /* Search parameters */ + Tcl_Obj *theLine; /* Object to append to */ + int *lenPtr; /* For returning the total length */ + int *extraLinesPtr; /* If non-NULL, will have its value + * incremented by the number of additional + * logical lines which are merged into this + * one by newlines being elided */ { TkTextLine *linePtr, *thisLinePtr; TkTextIndex curIndex; TkTextSegment *segPtr; TkText *textPtr = (TkText*)(searchSpecPtr->clientData); int nothingYet = 1; - + /* - * Extract the text from the line. + * Extract the text from the line. */ linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr, lineNum); @@ -3885,24 +3895,25 @@ TextSearchAddNextLine(lineNum, searchSpecPtr, theLine, lenPtr, extraLinesPtr) } curIndex.tree = textPtr->sharedTextPtr->tree; thisLinePtr = linePtr; - + while (thisLinePtr != NULL) { int elideWraps = 0; + curIndex.linePtr = thisLinePtr; curIndex.byteIndex = 0; for (segPtr = thisLinePtr->segPtr; segPtr != NULL; curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { - if (!searchSpecPtr->searchElide - && TkTextIsElided(textPtr, &curIndex, NULL)) { - /* - * If we reach the end of the logical line, and if we - * have at least one character in the string, then we - * continue wrapping to the next logical line. If - * there are no characters yet, then the entire line - * of characters is elided and there's no need to - * complicate matters by wrapping - we'll look at the - * next line in due course. + if (!searchSpecPtr->searchElide + && TkTextIsElided(textPtr, &curIndex, NULL)) { + /* + * If we reach the end of the logical line, and if we have at + * least one character in the string, then we continue + * wrapping to the next logical line. If there are no + * characters yet, then the entire line of characters is + * elided and there's no need to complicate matters by + * wrapping - we'll look at the next line in due course. */ + if (segPtr->nextPtr == NULL && !nothingYet) { elideWraps = 1; } @@ -3923,22 +3934,26 @@ TextSearchAddNextLine(lineNum, searchSpecPtr, theLine, lenPtr, extraLinesPtr) } thisLinePtr = TkBTreeNextLine(textPtr, thisLinePtr); if (thisLinePtr != NULL && extraLinesPtr != NULL) { - /* Tell our caller we have an extra line merged in */ + /* + * Tell our caller we have an extra line merged in. + */ + *extraLinesPtr = (*extraLinesPtr) + 1; } } - + /* - * If we're ignoring case, convert the line to lower case. - * There is no need to do this for regexp searches, since - * they handle a flag for this purpose. + * If we're ignoring case, convert the line to lower case. There is no + * need to do this for regexp searches, since they handle a flag for this + * purpose. */ + if (searchSpecPtr->exact && searchSpecPtr->noCase) { Tcl_SetObjLength(theLine, Tcl_UtfToLower(Tcl_GetString(theLine))); } - + if (lenPtr != NULL) { - if (searchSpecPtr->exact) { + if (searchSpecPtr->exact) { Tcl_GetStringFromObj(theLine, lenPtr); } else { *lenPtr = Tcl_GetCharLength(theLine); @@ -3955,38 +3970,34 @@ TextSearchAddNextLine(lineNum, searchSpecPtr, theLine, lenPtr, extraLinesPtr) * Stores information from a successful search. * * Results: - * 1 if the information was stored, 0 if the position at which - * the match was found actually falls outside the allowable - * search region (and therefore the search is actually - * complete). + * 1 if the information was stored, 0 if the position at which the match + * was found actually falls outside the allowable search region (and + * therefore the search is actually complete). * * Side effects: - * Memory may be allocated in the 'countPtr' and 'resPtr' fields - * of 'searchSpecPtr'. Each of those objects will have refCount - * zero and must eventually be freed or stored elsewhere as - * appropriate. + * Memory may be allocated in the 'countPtr' and 'resPtr' fields of + * 'searchSpecPtr'. Each of those objects will have refCount zero and + * must eventually be freed or stored elsewhere as appropriate. * *---------------------------------------------------------------------- */ -static int -TextSearchFoundMatch(lineNum, searchSpecPtr, clientData, theLine, - matchOffset, matchLength) - int lineNum; /* Line on which match was found */ - SearchSpec *searchSpecPtr; /* Search parameters */ - ClientData clientData; /* Token returned by the 'addNextLineProc', - * TextSearchAddNextLine. May be - * NULL, in which we case we must - * generate it (from lineNum) */ - Tcl_Obj *theLine; /* Text from current line, only - * accessed for exact searches, and - * is allowed to be NULL for regexp - * searches. */ - int matchOffset; /* Offset of found item in utf-8 bytes - * for exact search, Unicode chars - * for regexp */ - int matchLength; /* Length also in bytes/chars as per - * search type. */ +static int +TextSearchFoundMatch(lineNum, searchSpecPtr, clientData, theLine, matchOffset, + matchLength) + int lineNum; /* Line on which match was found. */ + SearchSpec *searchSpecPtr; /* Search parameters. */ + ClientData clientData; /* Token returned by the 'addNextLineProc', + * TextSearchAddNextLine. May be NULL, in + * which we case we must generate it (from + * lineNum). */ + Tcl_Obj *theLine; /* Text from current line, only accessed for + * exact searches, and is allowed to be NULL + * for regexp searches. */ + int matchOffset; /* Offset of found item in utf-8 bytes for + * exact search, Unicode chars for regexp */ + int matchLength; /* Length also in bytes/chars as per search + * type. */ { int numChars; int leftToScan; @@ -3996,63 +4007,70 @@ TextSearchFoundMatch(lineNum, searchSpecPtr, clientData, theLine, TkText *textPtr = (TkText*)(searchSpecPtr->clientData); if (lineNum == searchSpecPtr->stopLine) { - /* - * If the current index is on the wrong side of the stopIndex, - * then the item we just found is actually outside the acceptable - * range, and the search is over. + /* + * If the current index is on the wrong side of the stopIndex, then + * the item we just found is actually outside the acceptable range, + * and the search is over. */ - if (searchSpecPtr->backwards ^ - (matchOffset >= searchSpecPtr->stopOffset)) { + + if (searchSpecPtr->backwards ^ + (matchOffset >= searchSpecPtr->stopOffset)) { return 0; } } - + /* - * Calculate the character count, which may need augmenting - * if there are embedded windows or elidden text. + * Calculate the character count, which may need augmenting if there are + * embedded windows or elidden text. */ if (searchSpecPtr->exact) { CONST char *startOfLine = Tcl_GetString(theLine); + numChars = Tcl_NumUtfChars(startOfLine + matchOffset, matchLength); } else { numChars = matchLength; } - + /* - * The index information returned by the regular expression - * parser only considers textual information: it doesn't - * account for embedded windows, elided text (when we are not - * searching elided text) or any other non-textual info. - * Scan through the line's segments again to adjust both + * The index information returned by the regular expression parser only + * considers textual information: it doesn't account for embedded windows, + * elided text (when we are not searching elided text) or any other + * non-textual info. Scan through the line's segments again to adjust both * matchChar and matchCount. * - * We will walk through the segments of this line until we - * have either reached the end of the match or we have - * reached the end of the line. + * We will walk through the segments of this line until we have either + * reached the end of the match or we have reached the end of the line. */ linePtr = (TkTextLine *)clientData; if (linePtr == NULL) { - linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr, lineNum); + linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr, + lineNum); } - + curIndex.tree = textPtr->sharedTextPtr->tree; - /* Find the starting point */ + + /* + * Find the starting point. + */ + leftToScan = matchOffset; while (1) { - curIndex.linePtr = linePtr; + curIndex.linePtr = linePtr; curIndex.byteIndex = 0; - /* - * Note that we allow leftToScan to be zero because we want - * to skip over any preceding non-textual items. + + /* + * Note that we allow leftToScan to be zero because we want to skip + * over any preceding non-textual items. */ - for (segPtr = linePtr->segPtr; - leftToScan >= 0 && segPtr; segPtr = segPtr->nextPtr) { + + for (segPtr = linePtr->segPtr; leftToScan >= 0 && segPtr; + segPtr = segPtr->nextPtr) { if (segPtr->typePtr != &tkTextCharType) { matchOffset += segPtr->size; - } else if (!searchSpecPtr->searchElide - && TkTextIsElided(textPtr, &curIndex, NULL)) { + } else if (!searchSpecPtr->searchElide + && TkTextIsElided(textPtr, &curIndex, NULL)) { if (searchSpecPtr->exact) { matchOffset += segPtr->size; } else { @@ -4064,73 +4082,85 @@ TextSearchFoundMatch(lineNum, searchSpecPtr, clientData, theLine, curIndex.byteIndex += segPtr->size; } if (segPtr == NULL && leftToScan >= 0) { - /* This will only happen if we are eliding newlines */ + /* + * This will only happen if we are eliding newlines. + */ + linePtr = TkBTreeNextLine(textPtr, linePtr); if (linePtr == NULL) { - /* - * If we reach the end of the text, we have a serious - * problem, unless there's actually nothing left to look - * for. + /* + * If we reach the end of the text, we have a serious problem, + * unless there's actually nothing left to look for. */ + if (leftToScan == 0) { break; } else { Tcl_Panic("Reached end of text in a match"); } } - /* - * We've wrapped to the beginning of the next logical line, - * which has been merged with the previous one whose newline - * was elided. + + /* + * We've wrapped to the beginning of the next logical line, which + * has been merged with the previous one whose newline was elided. */ + lineNum++; matchOffset = 0; } else { break; } } - /* Calculate and store the found index in the result */ + + /* + * Calculate and store the found index in the result. + */ + if (searchSpecPtr->exact) { - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, lineNum, - matchOffset, &foundIndex); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, lineNum, + matchOffset, &foundIndex); } else { - TkTextMakeCharIndex(textPtr->sharedTextPtr->tree, textPtr, lineNum, - matchOffset, &foundIndex); + TkTextMakeCharIndex(textPtr->sharedTextPtr->tree, textPtr, lineNum, + matchOffset, &foundIndex); } + if (searchSpecPtr->all) { if (searchSpecPtr->resPtr == NULL) { searchSpecPtr->resPtr = Tcl_NewObj(); } - Tcl_ListObjAppendElement(NULL, searchSpecPtr->resPtr, + Tcl_ListObjAppendElement(NULL, searchSpecPtr->resPtr, TkTextNewIndexObj(textPtr, &foundIndex)); } else { - searchSpecPtr->resPtr = - TkTextNewIndexObj(textPtr, &foundIndex); - } - /* - * Find the end point. Here 'leftToScan' could be negative already - * as a result of the above loop if the segment we reached spanned - * the start of the string. When we add matchLength it will become - * non-negative. + searchSpecPtr->resPtr = TkTextNewIndexObj(textPtr, &foundIndex); + } + + /* + * Find the end point. Here 'leftToScan' could be negative already as a + * result of the above loop if the segment we reached spanned the start of + * the string. When we add matchLength it will become non-negative. */ + for (leftToScan += matchLength; leftToScan > 0; - curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { + curIndex.byteIndex += segPtr->size, segPtr = segPtr->nextPtr) { if (segPtr == NULL) { - /* - * We are on the next line -- this of course should only - * ever happen with searches which have matched across - * multiple lines + /* + * We are on the next line - this of course should only ever + * happen with searches which have matched across multiple lines. */ + linePtr = TkBTreeNextLine(textPtr, linePtr); segPtr = linePtr->segPtr; curIndex.linePtr = linePtr; curIndex.byteIndex = 0; } if (segPtr->typePtr != &tkTextCharType) { - /* Anything we didn't count in the search needs adding */ + /* + * Anything we didn't count in the search needs adding. + */ + numChars += segPtr->size; continue; - } else if (!searchSpecPtr->searchElide - && TkTextIsElided(textPtr, &curIndex, NULL)) { + } else if (!searchSpecPtr->searchElide + && TkTextIsElided(textPtr, &curIndex, NULL)) { numChars += Tcl_NumUtfChars(segPtr->body.chars, -1); continue; } @@ -4140,9 +4170,11 @@ TextSearchFoundMatch(lineNum, searchSpecPtr, clientData, theLine, leftToScan -= Tcl_NumUtfChars(segPtr->body.chars, -1); } } - /* - * Now store the count result, if it is wanted + + /* + * Now store the count result, if it is wanted. */ + if (searchSpecPtr->varPtr != NULL) { Tcl_Obj *tmpPtr = Tcl_NewIntObj(numChars); if (searchSpecPtr->all) { @@ -4165,27 +4197,23 @@ TextSearchFoundMatch(lineNum, searchSpecPtr, clientData, theLine, * Parses a string description of a set of tab stops. * * Results: - * The return value is a pointer to a malloc'ed structure holding - * parsed information about the tab stops. If an error occurred - * then the return value is NULL and an error message is left in - * the interp's result. + * The return value is a pointer to a malloc'ed structure holding parsed + * information about the tab stops. If an error occurred then the return + * value is NULL and an error message is left in the interp's result. * * Side effects: - * Memory is allocated for the structure that is returned. It is - * up to the caller to free this structure when it is no longer - * needed. + * Memory is allocated for the structure that is returned. It is up to + * the caller to free this structure when it is no longer needed. * *---------------------------------------------------------------------- */ TkTextTabArray * TkTextGetTabs(interp, textPtr, stringPtr) - Tcl_Interp *interp; /* Used for error reporting. */ - TkText *textPtr; /* Information about the - * text widget. */ - Tcl_Obj *stringPtr; /* Description of the tab stops. - * See the text manual entry for - * details. */ + Tcl_Interp *interp; /* Used for error reporting. */ + TkText *textPtr; /* Information about the text widget. */ + Tcl_Obj *stringPtr; /* Description of the tab stops. See the text + * manual entry for details. */ { int objc, i, count; Tcl_Obj **objv; @@ -4193,20 +4221,19 @@ TkTextGetTabs(interp, textPtr, stringPtr) TkTextTab *tabPtr; Tcl_UniChar ch; double prevStop, lastStop; - - /* Map these strings to TkTextTabAlign values */ - + /* + * Map these strings to TkTextTabAlign values. + */ static CONST char *tabOptionStrings[] = { - "left", "right", "center", "numeric", (char *) NULL + "left", "right", "center", "numeric", (char *) NULL }; - + if (Tcl_ListObjGetElements(interp, stringPtr, &objc, &objv) != TCL_OK) { return NULL; } /* - * First find out how many entries we need to allocate in the - * tab array. + * First find out how many entries we need to allocate in the tab array. */ count = 0; @@ -4218,8 +4245,7 @@ TkTextGetTabs(interp, textPtr, stringPtr) } /* - * Parse the elements of the list one at a time to fill in the - * array. + * Parse the elements of the list one at a time to fill in the array. */ tabArrayPtr = (TkTextTabArray *) ckalloc((unsigned) @@ -4227,99 +4253,103 @@ TkTextGetTabs(interp, textPtr, stringPtr) tabArrayPtr->numTabs = 0; prevStop = 0.0; lastStop = 0.0; - for (i = 0, tabPtr = &tabArrayPtr->tabs[0]; i < objc; i++, tabPtr++) { + for (i = 0, tabPtr = &tabArrayPtr->tabs[0]; i < objc; i++, tabPtr++) { int index; - - /* - * This will round fractional pixels above 0.5 upwards, and - * otherwise downwards, to find the right integer pixel - * position. + + /* + * This will round fractional pixels above 0.5 upwards, and otherwise + * downwards, to find the right integer pixel position. */ - if (Tk_GetPixelsFromObj(interp, textPtr->tkwin, objv[i], - &tabPtr->location) != TCL_OK) { + + if (Tk_GetPixelsFromObj(interp, textPtr->tkwin, objv[i], + &tabPtr->location) != TCL_OK) { goto error; } if (tabPtr->location <= 0) { - Tcl_AppendResult(interp, - "tab stop \"", Tcl_GetString(objv[i]), - "\" is not at a positive distance", NULL); + Tcl_AppendResult(interp, "tab stop \"", Tcl_GetString(objv[i]), + "\" is not at a positive distance", NULL); goto error; } - + prevStop = lastStop; - if (Tk_GetMMFromObj(interp, textPtr->tkwin, objv[i], - &lastStop) != TCL_OK) { + if (Tk_GetMMFromObj(interp, textPtr->tkwin, objv[i], + &lastStop) != TCL_OK) { goto error; } lastStop *= WidthOfScreen(Tk_Screen(textPtr->tkwin)); lastStop /= WidthMMOfScreen(Tk_Screen(textPtr->tkwin)); - + if (i > 0 && (tabPtr->location <= (tabPtr-1)->location)) { - /* - * This tab is actually to the left of the previous - * one, which is illegal. + /* + * This tab is actually to the left of the previous one, which is + * illegal. */ + #ifdef _TK_ALLOW_DECREASING_TABS - /* - * Force the tab to be a typical character width to the - * right of the previous one, and update the 'lastStop' - * with the changed position. + /* + * Force the tab to be a typical character width to the right of + * the previous one, and update the 'lastStop' with the changed + * position. */ + if (textPtr->charWidth > 0) { - tabPtr->location = (tabPtr-1)->location + textPtr->charWidth; + tabPtr->location = (tabPtr-1)->location + textPtr->charWidth; } else { tabPtr->location = (tabPtr-1)->location + 8; } lastStop = tabPtr->location; #else - Tcl_AppendResult(interp, - "tabs must be monotonically increasing, but \"", - Tcl_GetString(objv[i]), - "\" is smaller than or equal to the previous tab", - NULL); + Tcl_AppendResult(interp, + "tabs must be monotonically increasing, but \"", + Tcl_GetString(objv[i]), + "\" is smaller than or equal to the previous tab", + NULL); goto error; -#endif +#endif /* _TK_ALLOW_DECREASING_TABS */ } - + tabArrayPtr->numTabs++; /* - * See if there is an explicit alignment in the next list - * element. Otherwise just use "left". + * See if there is an explicit alignment in the next list element. + * Otherwise just use "left". */ tabPtr->alignment = LEFT; if ((i+1) == objc) { continue; } - /* There may be a more efficient way of getting this */ + + /* + * There may be a more efficient way of getting this. + */ + Tcl_UtfToUniChar(Tcl_GetString(objv[i+1]), &ch); if (!Tcl_UniCharIsAlpha(ch)) { continue; } i += 1; - - if (Tcl_GetIndexFromObj(interp, objv[i], tabOptionStrings, - "tab alignment", 0, &index) != TCL_OK) { + + if (Tcl_GetIndexFromObj(interp, objv[i], tabOptionStrings, + "tab alignment", 0, &index) != TCL_OK) { goto error; } tabPtr->alignment = ((TkTextTabAlign)index); } - + /* - * For when we need to interpolate tab stops, store - * these two so we know the tab stop size to very - * high precision. With the above checks, we can - * guarantee that tabIncrement is strictly positive - * here. + * For when we need to interpolate tab stops, store these two so we know + * the tab stop size to very high precision. With the above checks, we can + * guarantee that tabIncrement is strictly positive here. */ + tabArrayPtr->lastTab = lastStop; tabArrayPtr->tabIncrement = lastStop - prevStop; - + return tabArrayPtr; - error: + error: ckfree((char *) tabArrayPtr); return NULL; } @@ -4330,8 +4360,8 @@ TkTextGetTabs(interp, textPtr, stringPtr) * TextDumpCmd -- * * Return information about the text, tags, marks, and embedded windows - * and images in a text widget. See the man page for the description - * of the text dump operation for all the details. + * and images in a text widget. See the man page for the description of + * the text dump operation for all the details. * * Results: * A standard Tcl result. @@ -4405,7 +4435,7 @@ TextDumpCmd(textPtr, interp, objc, objv) case DUMP_CMD: arg++; if (arg >= objc) { - Tcl_AppendResult(interp, "Usage: ", Tcl_GetString(objv[0]), + Tcl_AppendResult(interp, "Usage: ", Tcl_GetString(objv[0]), " dump ?-all -image -text -mark -tag -window? ", "?-command script? index ?index2?", NULL); return TCL_ERROR; @@ -4417,7 +4447,7 @@ TextDumpCmd(textPtr, interp, objc, objv) } } if (arg >= objc || arg+2 < objc) { - Tcl_AppendResult(interp, "Usage: ", Tcl_GetString(objv[0]), + Tcl_AppendResult(interp, "Usage: ", Tcl_GetString(objv[0]), " dump ?-all -image -text -mark -tag -window? ", "?-command script? index ?index2?", NULL); return TCL_ERROR; @@ -4436,6 +4466,7 @@ TextDumpCmd(textPtr, interp, objc, objv) } else { int length; char *str; + if (TkTextGetObjIndex(interp, textPtr, objv[arg], &index2) != TCL_OK) { return TCL_ERROR; } @@ -4465,12 +4496,14 @@ TextDumpCmd(textPtr, interp, objc, objv) DumpLine(interp, textPtr, what, index2.linePtr, 0, index2.byteIndex, lineno, command); } + /* * Special case to get the leftovers hiding at the end mark. */ + if (atEnd) { DumpLine(interp, textPtr, what & ~TK_DUMP_TEXT, index2.linePtr, - 0, 1, lineno, command); + 0, 1, lineno, command); } return TCL_OK; } @@ -4479,16 +4512,16 @@ TextDumpCmd(textPtr, interp, objc, objv) *---------------------------------------------------------------------- * * DumpLine - * - * Return information about a given text line from character - * position "start" up to, but not including, "end". + * + * Return information about a given text line from character position + * "start" up to, but not including, "end". * * Results: * A standard Tcl result. * * Side effects: * None, but see DumpSegment. - * + * *---------------------------------------------------------------------- */ static void @@ -4521,6 +4554,7 @@ DumpLine(interp, textPtr, what, linePtr, startByte, endByte, lineno, command) char savedChar; /* Last char used in the seg */ int last = segPtr->size; /* Index of savedChar */ int first = 0; /* Index of first char in seg */ + if (offset + segPtr->size > endByte) { last = endByte - offset; } @@ -4529,62 +4563,65 @@ DumpLine(interp, textPtr, what, linePtr, startByte, endByte, lineno, command) } savedChar = segPtr->body.chars[last]; segPtr->body.chars[last] = '\0'; - - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, lineno, - offset + first, &index); + + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, lineno, + offset + first, &index); DumpSegment(textPtr, interp, "text", segPtr->body.chars + first, command, &index, what); segPtr->body.chars[last] = savedChar; } else if ((offset >= startByte)) { if ((what & TK_DUMP_MARK) && (segPtr->typePtr->name[0] == 'm')) { char *name; - TkTextMark *markPtr = (TkTextMark *)&segPtr->body; + TkTextMark *markPtr = (TkTextMark *) &segPtr->body; + if (segPtr == textPtr->insertMarkPtr) { name = "insert"; } else if (segPtr == textPtr->currentMarkPtr) { name = "current"; } else { - name = Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, - markPtr->hPtr); + name = Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, + markPtr->hPtr); } - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - lineno, offset, &index); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + lineno, offset, &index); DumpSegment(textPtr, interp, "mark", name, command, &index, what); } else if ((what & TK_DUMP_TAG) && - (segPtr->typePtr == &tkTextToggleOnType)) { - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - lineno, offset, &index); + (segPtr->typePtr == &tkTextToggleOnType)) { + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + lineno, offset, &index); DumpSegment(textPtr, interp, "tagon", - segPtr->body.toggle.tagPtr->name, - command, &index, what); - } else if ((what & TK_DUMP_TAG) && - (segPtr->typePtr == &tkTextToggleOffType)) { - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - lineno, offset, &index); + segPtr->body.toggle.tagPtr->name, command, &index, + what); + } else if ((what & TK_DUMP_TAG) && + (segPtr->typePtr == &tkTextToggleOffType)) { + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + lineno, offset, &index); DumpSegment(textPtr, interp, "tagoff", - segPtr->body.toggle.tagPtr->name, - command, &index, what); - } else if ((what & TK_DUMP_IMG) && - (segPtr->typePtr->name[0] == 'i')) { + segPtr->body.toggle.tagPtr->name, command, &index, + what); + } else if ((what & TK_DUMP_IMG) && + (segPtr->typePtr->name[0] == 'i')) { TkTextEmbImage *eiPtr = (TkTextEmbImage *)&segPtr->body; - char *name = (eiPtr->name == NULL) ? "" : eiPtr->name; - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - lineno, offset, &index); - DumpSegment(textPtr, interp, "image", name, - command, &index, what); - } else if ((what & TK_DUMP_WIN) && - (segPtr->typePtr->name[0] == 'w')) { + char *name = (eiPtr->name == NULL) ? "" : eiPtr->name; + + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + lineno, offset, &index); + DumpSegment(textPtr, interp, "image", name, command, &index, + what); + } else if ((what & TK_DUMP_WIN) && + (segPtr->typePtr->name[0] == 'w')) { TkTextEmbWindow *ewPtr = (TkTextEmbWindow *)&segPtr->body; char *pathname; + if (ewPtr->tkwin == (Tk_Window) NULL) { pathname = ""; } else { pathname = Tk_PathName(ewPtr->tkwin); } - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, - lineno, offset, &index); - DumpSegment(textPtr, interp, "window", pathname, - command, &index, what); + TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, + lineno, offset, &index); + DumpSegment(textPtr, interp, "window", pathname, command, + &index, what); } } } @@ -4594,18 +4631,19 @@ DumpLine(interp, textPtr, what, linePtr, startByte, endByte, lineno, command) *---------------------------------------------------------------------- * * DumpSegment - * - * Either append information about the current segment to the result, - * or make a script callback with that information as arguments. + * + * Either append information about the current segment to the result, or + * make a script callback with that information as arguments. * * Results: * None * * Side effects: * Either evals the callback or appends elements to the result string. - * + * *---------------------------------------------------------------------- */ + static int DumpSegment(textPtr, interp, key, value, command, index, what) TkText *textPtr; @@ -4613,10 +4651,11 @@ DumpSegment(textPtr, interp, key, value, command, index, what) CONST char *key; /* Segment type key */ CONST char *value; /* Segment value */ CONST char *command; /* Script callback */ - CONST TkTextIndex *index; /* index with line/byte position info */ + CONST TkTextIndex *index; /* index with line/byte position info */ int what; /* Look for TK_DUMP_INDEX bit */ { char buffer[TK_POS_CHARS]; + TkTextPrintIndex(textPtr, index, buffer); if (command == NULL) { Tcl_AppendElement(interp, key); @@ -4627,6 +4666,7 @@ DumpSegment(textPtr, interp, key, value, command, index, what) CONST char *argv[4]; char *list; int result; + argv[0] = key; argv[1] = value; argv[2] = buffer; @@ -4642,41 +4682,40 @@ DumpSegment(textPtr, interp, key, value, command, index, what) *---------------------------------------------------------------------- * * TextEditUndo -- - * - * undo the last change. + * + * Undo the last change. * * Results: - * None + * None. * * Side effects: - * None. - * + * Apart from manipulating the undo and redo stacks, the state of the + * rest of the widget may also change (due to whatever is being undone). + * *---------------------------------------------------------------------- */ static int TextEditUndo(textPtr) - TkText *textPtr; /* Overall information about text widget. */ + TkText *textPtr; /* Overall information about text widget. */ { int status; if (!textPtr->sharedTextPtr->undo) { - return TCL_OK; + return TCL_OK; } - /* Turn off the undo feature */ - textPtr->sharedTextPtr->undo = 0; + /* + * Turn off the undo feature while we revert a compound action. Note that + * the dirty counter counts backwards while we are undoing... + */ - /* The dirty counter should count downwards as we are undoing things */ + textPtr->sharedTextPtr->undo = 0; textPtr->sharedTextPtr->isDirtyIncrement = -1; - /* revert one compound action */ status = TkUndoRevert(textPtr->sharedTextPtr->undoStack); - /* Restore the isdirty increment */ textPtr->sharedTextPtr->isDirtyIncrement = 1; - - /* Turn back on the undo feature */ textPtr->sharedTextPtr->undo = 1; return status; @@ -4686,37 +4725,39 @@ TextEditUndo(textPtr) *---------------------------------------------------------------------- * * TextEditRedo -- - * - * redo the last undone change. + * + * Redo the last undone change. * * Results: - * None + * None. * * Side effects: - * None. - * + * Apart from manipulating the undo and redo stacks, the state of the + * rest of the widget may also change (due to whatever is being redone). + * *---------------------------------------------------------------------- */ static int TextEditRedo(textPtr) - TkText *textPtr; /* Overall information about text widget. */ + TkText *textPtr; /* Overall information about text widget. */ { int status; if (!textPtr->sharedTextPtr->undo) { - return TCL_OK; + return TCL_OK; } - /* Turn off the undo feature temporarily */ + /* + * Turn off the undo feature temporarily while we revert a previously + * undone compound action. + */ + textPtr->sharedTextPtr->undo = 0; - /* reapply one compound action */ status = TkUndoApply(textPtr->sharedTextPtr->undoStack); - /* Turn back on the undo feature */ textPtr->sharedTextPtr->undo = 1; - return status; } @@ -4725,126 +4766,122 @@ TextEditRedo(textPtr) * * TextEditCmd -- * - * Handle the subcommands to "$text edit ...". - * See documentation for details. + * Handle the subcommands to "$text edit ...". See documentation for + * details. * * Results: - * None + * None * * Side effects: - * None. - * + * None. + * *---------------------------------------------------------------------- */ static int TextEditCmd(textPtr, interp, objc, objv) - TkText *textPtr; /* Information about text widget. */ - Tcl_Interp *interp; /* Current interpreter. */ + TkText *textPtr; /* Information about text widget. */ + Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int index; - + static CONST char *editOptionStrings[] = { - "modified", "redo", "reset", "separator", "undo", (char *) NULL + "modified", "redo", "reset", "separator", "undo", (char *) NULL }; enum editOptions { EDIT_MODIFIED, EDIT_REDO, EDIT_RESET, EDIT_SEPARATOR, EDIT_UNDO }; - + if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?"); return TCL_ERROR; } - - if (Tcl_GetIndexFromObj(interp, objv[2], editOptionStrings, - "edit option", 0, &index) != TCL_OK) { + + if (Tcl_GetIndexFromObj(interp, objv[2], editOptionStrings, + "edit option", 0, &index) != TCL_OK) { return TCL_ERROR; } - switch ((enum editOptions)index) { - case EDIT_MODIFIED: { - if (objc == 3) { - Tcl_SetObjResult(interp, - Tcl_NewBooleanObj(textPtr->sharedTextPtr->isDirty)); - } else if (objc != 4) { - Tcl_WrongNumArgs(interp, 3, objv, "?boolean?"); - return TCL_ERROR; - } else { - int setModified; - XEvent event; - if (Tcl_GetBooleanFromObj(interp, objv[3], &setModified) - != TCL_OK) { - return TCL_ERROR; - } - /* - * Set or reset the dirty info and trigger a Modified event. - */ + switch ((enum editOptions) index) { + case EDIT_MODIFIED: + if (objc == 3) { + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(textPtr->sharedTextPtr->isDirty)); + } else if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "?boolean?"); + return TCL_ERROR; + } else { + int setModified; + XEvent event; - if (setModified) { - textPtr->sharedTextPtr->isDirty = 1; - textPtr->sharedTextPtr->modifiedSet = 1; - } else { - textPtr->sharedTextPtr->isDirty = 0; - textPtr->sharedTextPtr->modifiedSet = 0; - } + if (Tcl_GetBooleanFromObj(interp, objv[3], + &setModified) != TCL_OK) { + return TCL_ERROR; + } - /* - * Send an event that the text was modified. This is - * equivalent to "event generate $textWidget <<Modified>>" - */ + /* + * Set or reset the dirty info and trigger a Modified event. + */ - memset((VOID *) &event, 0, sizeof(event)); - event.xany.type = VirtualEvent; - event.xany.serial = NextRequest(Tk_Display(textPtr->tkwin)); - event.xany.send_event = False; - event.xany.window = Tk_WindowId(textPtr->tkwin); - event.xany.display = Tk_Display(textPtr->tkwin); - ((XVirtualEvent *) &event)->name = Tk_GetUid("Modified"); - Tk_HandleEvent(&event); + if (setModified) { + textPtr->sharedTextPtr->isDirty = 1; + textPtr->sharedTextPtr->modifiedSet = 1; + } else { + textPtr->sharedTextPtr->isDirty = 0; + textPtr->sharedTextPtr->modifiedSet = 0; } - break; + + /* + * Send an event that the text was modified. This is equivalent to + * "event generate $textWidget <<Modified>>" + */ + + memset((VOID *) &event, 0, sizeof(event)); + event.xany.type = VirtualEvent; + event.xany.serial = NextRequest(Tk_Display(textPtr->tkwin)); + event.xany.send_event = False; + event.xany.window = Tk_WindowId(textPtr->tkwin); + event.xany.display = Tk_Display(textPtr->tkwin); + ((XVirtualEvent *) &event)->name = Tk_GetUid("Modified"); + Tk_HandleEvent(&event); } - case EDIT_REDO: { - if (objc != 3) { - Tcl_WrongNumArgs(interp, 3, objv, NULL); - return TCL_ERROR; - } - if (TextEditRedo(textPtr)) { - Tcl_AppendResult(interp, "nothing to redo", (char *) NULL); - return TCL_ERROR; - } - break; + break; + case EDIT_REDO: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; } - case EDIT_RESET: { - if (objc != 3) { - Tcl_WrongNumArgs(interp, 3, objv, NULL); - return TCL_ERROR; - } - TkUndoClearStacks(textPtr->sharedTextPtr->undoStack); - break; + if (TextEditRedo(textPtr)) { + Tcl_AppendResult(interp, "nothing to redo", (char *) NULL); + return TCL_ERROR; } - case EDIT_SEPARATOR: { - if (objc != 3) { - Tcl_WrongNumArgs(interp, 3, objv, NULL); - return TCL_ERROR; - } - TkUndoInsertUndoSeparator(textPtr->sharedTextPtr->undoStack); - break; + break; + case EDIT_RESET: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; } - case EDIT_UNDO: { - if (objc != 3) { - Tcl_WrongNumArgs(interp, 3, objv, NULL); - return TCL_ERROR; - } - if (TextEditUndo(textPtr)) { - Tcl_AppendResult(interp, "nothing to undo", - (char *) NULL); - return TCL_ERROR; - } - break; - } + TkUndoClearStacks(textPtr->sharedTextPtr->undoStack); + break; + case EDIT_SEPARATOR: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; + } + TkUndoInsertUndoSeparator(textPtr->sharedTextPtr->undoStack); + break; + case EDIT_UNDO: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; + } + if (TextEditUndo(textPtr)) { + Tcl_AppendResult(interp, "nothing to undo", (char *) NULL); + return TCL_ERROR; + } + break; } return TCL_OK; } @@ -4853,49 +4890,51 @@ TextEditCmd(textPtr, interp, objc, objv) *---------------------------------------------------------------------- * * TextGetText -- - * - * Returns the text from indexPtr1 to indexPtr2, placing that text - * in a string object which is returned with a refCount of zero. - * - * Since the amount of text may potentially be several megabytes (e.g. - * in text editors built on the text widget), efficiency is very - * important. We may want to investigate the efficiency of the - * Tcl_AppendToObj more carefully (e.g. if we know we are going to be - * appending several thousand lines, we could attempt to pre-allocate - * a larger space). - * - * Also the result is built up as a utf-8 string, but, if we knew - * we wanted it as Unicode, we could potentially save a huge - * conversion by building it up as Unicode directly. This could - * be as simple as replacing Tcl_NewObj by Tcl_NewUnicodeObj. + * + * Returns the text from indexPtr1 to indexPtr2, placing that text in a + * string object which is returned with a refCount of zero. + * + * Since the amount of text may potentially be several megabytes (e.g. + * in text editors built on the text widget), efficiency is very + * important. We may want to investigate the efficiency of the + * Tcl_AppendToObj more carefully (e.g. if we know we are going to be + * appending several thousand lines, we could attempt to pre-allocate a + * larger space). + * + * Also the result is built up as a utf-8 string, but, if we knew we + * wanted it as Unicode, we could potentially save a huge conversion by + * building it up as Unicode directly. This could be as simple as + * replacing Tcl_NewObj by Tcl_NewUnicodeObj. * * Results: - * Tcl_Obj of string type containing the specified text. If the - * visibleOnly flag is set to 1, then only those characters which - * are not elided will be returned. Otherwise (flag is 0) all - * characters in the given range are returned. + * Tcl_Obj of string type containing the specified text. If the + * visibleOnly flag is set to 1, then only those characters which are not + * elided will be returned. Otherwise (flag is 0) all characters in the + * given range are returned. * * Side effects: - * Memory will be allocated for the new object. Remember to free it if - * it isn't going to be stored appropriately. - * + * Memory will be allocated for the new object. Remember to free it if it + * isn't going to be stored appropriately. + * *---------------------------------------------------------------------- */ -static Tcl_Obj* +static Tcl_Obj* TextGetText(textPtr, indexPtr1,indexPtr2, visibleOnly) - CONST TkText *textPtr; /* Information about text widget. */ - CONST TkTextIndex *indexPtr1; /* Get text from this index... */ - CONST TkTextIndex *indexPtr2; /* ...to this index */ - int visibleOnly; /* If non-zero, then only return - * non-elided characters. */ + CONST TkText *textPtr; /* Information about text widget. */ + CONST TkTextIndex *indexPtr1; + /* Get text from this index... */ + CONST TkTextIndex *indexPtr2; + /* ...to this index. */ + int visibleOnly; /* If non-zero, then only return non-elided + * characters. */ { TkTextIndex tmpIndex; Tcl_Obj *resultPtr = Tcl_NewObj(); - - TkTextMakeByteIndex(indexPtr1->tree, textPtr, - TkBTreeLinesTo(textPtr, indexPtr1->linePtr), - indexPtr1->byteIndex, &tmpIndex); + + TkTextMakeByteIndex(indexPtr1->tree, textPtr, + TkBTreeLinesTo(textPtr, indexPtr1->linePtr), + indexPtr1->byteIndex, &tmpIndex); if (TkTextIndexCmp(indexPtr1, indexPtr2) < 0) { while (1) { @@ -4905,25 +4944,27 @@ TextGetText(textPtr, indexPtr1,indexPtr2, visibleOnly) segPtr = TkTextIndexToSeg(&tmpIndex, &offset); last = segPtr->size; if (tmpIndex.linePtr == indexPtr2->linePtr) { - /* - * The last line that was requested must be handled - * carefully, because we may need to break out of this - * loop in the middle of the line + /* + * The last line that was requested must be handled carefully, + * because we may need to break out of this loop in the middle + * of the line. */ + if (indexPtr2->byteIndex == tmpIndex.byteIndex) { break; } else { - int last2; - last2 = indexPtr2->byteIndex - tmpIndex.byteIndex + offset; + int last2 = + indexPtr2->byteIndex - tmpIndex.byteIndex + offset; + if (last2 < last) { last = last2; } } } if (segPtr->typePtr == &tkTextCharType) { - if (!visibleOnly || !TkTextIsElided(textPtr, &tmpIndex, NULL)) { + if (!visibleOnly || !TkTextIsElided(textPtr,&tmpIndex,NULL)) { Tcl_AppendToObj(resultPtr, segPtr->body.chars + offset, - last - offset); + last - offset); } } TkTextIndexForwBytes(textPtr, &tmpIndex, last-offset, &tmpIndex); @@ -4936,39 +4977,40 @@ TextGetText(textPtr, indexPtr1,indexPtr2, visibleOnly) *---------------------------------------------------------------------- * * UpdateDirtyFlag -- - * - * Increases the dirtyness of the text widget + * + * Increases the dirtyness of the text widget * * Results: - * None + * None * * Side effects: - * None. - * + * None. + * *---------------------------------------------------------------------- */ -static void -UpdateDirtyFlag (sharedTextPtr) - TkSharedText *sharedTextPtr; /* Information about text widget. */ +static void +UpdateDirtyFlag(sharedTextPtr) + TkSharedText *sharedTextPtr;/* Information about text widget. */ { int oldDirtyFlag; if (sharedTextPtr->modifiedSet) { - return; + return; } oldDirtyFlag = sharedTextPtr->isDirty; sharedTextPtr->isDirty += sharedTextPtr->isDirtyIncrement; if (sharedTextPtr->isDirty == 0 || oldDirtyFlag == 0) { TkText *textPtr; - for (textPtr = sharedTextPtr->peers; textPtr != NULL; - textPtr = textPtr->next) { - XEvent event; + for (textPtr = sharedTextPtr->peers; textPtr != NULL; + textPtr = textPtr->next) { /* - * Send an event that the text was modified. This is equivalent to - * "event generate $textWidget <<Modified>>" + * Send an event that the text was modified. This is equivalent to + * event generate $textWidget <<Modified>> */ + XEvent event; + memset((VOID *) &event, 0, sizeof(event)); event.xany.type = VirtualEvent; event.xany.serial = NextRequest(Tk_Display(textPtr->tkwin)); @@ -4986,68 +5028,75 @@ UpdateDirtyFlag (sharedTextPtr) * * SearchPerform -- * - * Overall control of search process. Is given a pattern, a - * starting index and an ending index, and attempts to perform a - * search. This procedure is actually completely independent of Tk, - * and could in the future be split off. - * + * Overall control of search process. Is given a pattern, a starting + * index and an ending index, and attempts to perform a search. This + * function is actually completely independent of Tk, and could in the + * future be split off. + * * Results: - * Standard Tcl result code. In particular, if fromPtr or toPtr - * are not considered valid by the 'lineIndexProc', an error - * will be thrown and no search performed. + * Standard Tcl result code. In particular, if fromPtr or toPtr are not + * considered valid by the 'lineIndexProc', an error will be thrown and + * no search performed. * * Side effects: * See 'SearchCore'. - * + * *---------------------------------------------------------------------- */ static int SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr) - Tcl_Interp *interp; /* For error messages */ - SearchSpec *searchSpecPtr; /* Search parameters */ - Tcl_Obj *patObj; /* Contains an exact string or a - * regexp pattern. Must have a - * refCount > 0 */ - Tcl_Obj *fromPtr; /* Contains information describing - * the first index */ - Tcl_Obj *toPtr; /* NULL or information describing - * the last index */ + Tcl_Interp *interp; /* For error messages */ + SearchSpec *searchSpecPtr; /* Search parameters */ + Tcl_Obj *patObj; /* Contains an exact string or a regexp + * pattern. Must have a refCount > 0 */ + Tcl_Obj *fromPtr; /* Contains information describing the first + * index */ + Tcl_Obj *toPtr; /* NULL or information describing the last + * index */ { - /* - * Find the starting line and starting offset (measured in Unicode - * chars for regexp search, utf-8 bytes for exact search) + /* + * Find the starting line and starting offset (measured in Unicode chars + * for regexp search, utf-8 bytes for exact search). */ - if ((*searchSpecPtr->lineIndexProc)(interp, fromPtr, searchSpecPtr, + + if ((*searchSpecPtr->lineIndexProc)(interp, fromPtr, searchSpecPtr, &searchSpecPtr->startLine, &searchSpecPtr->startOffset) != TCL_OK) { return TCL_ERROR; } - /* + /* * Find the optional end location, similarly. */ + if (toPtr != NULL) { CONST TkTextIndex *indexToPtr, *indexFromPtr; TkText *textPtr = (TkText*)(searchSpecPtr->clientData); - + indexToPtr = TkTextGetIndexFromObj(interp, textPtr, toPtr); if (indexToPtr == NULL) { return TCL_ERROR; } indexFromPtr = TkTextGetIndexFromObj(interp, textPtr, fromPtr); - /* - * Check for any empty search range here. It might be better - * in the future to embed that in SearchCore (whose default - * behaviour is to wrap when given a negative search range). + + /* + * Check for any empty search range here. It might be better in the + * future to embed that in SearchCore (whose default behaviour is to + * wrap when given a negative search range). */ + if (searchSpecPtr->backwards) { - if (TkTextIndexCmp(indexFromPtr, indexToPtr) == -1) return TCL_OK; + if (TkTextIndexCmp(indexFromPtr, indexToPtr) == -1) { + return TCL_OK; + } } else { - if (TkTextIndexCmp(indexFromPtr, indexToPtr) == 1) return TCL_OK; + if (TkTextIndexCmp(indexFromPtr, indexToPtr) == 1) { + return TCL_OK; + } } - - if ((*searchSpecPtr->lineIndexProc)(interp, toPtr, searchSpecPtr, + + if ((*searchSpecPtr->lineIndexProc)(interp, toPtr, searchSpecPtr, &searchSpecPtr->stopLine, &searchSpecPtr->stopOffset) != TCL_OK) { return TCL_ERROR; @@ -5057,10 +5106,9 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr) } /* - * Scan through all of the lines of the text circularly, starting - * at the given index. 'patObj' is the pattern which may be an - * exact string or a regexp pattern depending on the flags in - * searchSpecPtr. + * Scan through all of the lines of the text circularly, starting at the + * given index. 'patObj' is the pattern which may be an exact string or a + * regexp pattern depending on the flags in searchSpecPtr. */ return SearchCore(interp, searchSpecPtr, patObj); @@ -5071,14 +5119,12 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr) * * SearchCore -- * - * The core of the search procedure. This procedure is actually - * completely independent of Tk, and could in the future be split - * off. + * The core of the search function. This function is actually completely + * independent of Tk, and could in the future be split off. * - * The function assumes regexp-based searches operate on Unicode - * strings, and exact searches on utf-8 strings. Therefore the - * 'foundMatchProc' and 'addLineProc' need to be aware of this - * distinction. + * The function assumes regexp-based searches operate on Unicode strings, + * and exact searches on utf-8 strings. Therefore the 'foundMatchProc' + * and 'addLineProc' need to be aware of this distinction. * * Results: * Standard Tcl result code. @@ -5087,46 +5133,50 @@ SearchPerform(interp, searchSpecPtr, patObj, fromPtr, toPtr) * Only those of the 'searchSpecPtr->foundMatchProc' which is called * whenever a match is found. * - * Note that the way matching across multiple lines is implemented, - * we start afresh with each line we have available, even though we - * may already have examined the contents of that line (and further - * ones) if we were attempting a multi-line match using the previous - * line. This means there may be ways to speed this up a lot by not - * throwing away all the multi-line information one has accumulated. - * Profiling should be done to see where the bottlenecks lie before - * attempting this, however. We would also need to be very careful - * such optimisation keep within the specified search bounds. + * Note that the way matching across multiple lines is implemented, we + * start afresh with each line we have available, even though we may + * already have examined the contents of that line (and further ones) if + * we were attempting a multi-line match using the previous line. This + * means there may be ways to speed this up a lot by not throwing away + * all the multi-line information one has accumulated. Profiling should + * be done to see where the bottlenecks lie before attempting this, + * however. We would also need to be very careful such optimisation keep + * within the specified search bounds. * *---------------------------------------------------------------------- */ static int SearchCore(interp, searchSpecPtr, patObj) - Tcl_Interp *interp; /* For error messages */ - SearchSpec *searchSpecPtr; /* Search parameters */ - Tcl_Obj *patObj; /* Contains an exact string or a - * regexp pattern. Must have a - * refCount > 0 */ + Tcl_Interp *interp; /* For error messages */ + SearchSpec *searchSpecPtr; /* Search parameters */ + Tcl_Obj *patObj; /* Contains an exact string or a regexp + * pattern. Must have a refCount > 0 */ { - int passes; /* - * For exact searches these are utf-8 char* offsets, for regexp - * searches they are Unicode char offsets + * For exact searches these are utf-8 char* offsets, for regexp searches + * they are Unicode char offsets. */ + int firstOffset, lastOffset, matchOffset, matchLength; + int passes; int lineNum = searchSpecPtr->startLine; int code = TCL_OK; Tcl_Obj *theLine; int alreadySearchOffset = -1; - - Tcl_RegExp regexp = NULL; /* For regexp searches only */ - /* - * These items are for backward regexp searches only. They are for - * two purposes: to allow us to report backwards matches in the - * correct order, even though the implementation uses repeated - * forward searches; and to provide for overlap checking between - * backwards matches on different text lines. + + CONST char *pattern = NULL; /* For exact searches only. */ + int firstNewLine = -1; /* For exact searches only. */ + Tcl_RegExp regexp = NULL; /* For regexp searches only. */ + + /* + * These items are for backward regexp searches only. They are for two + * purposes: to allow us to report backwards matches in the correct order, + * even though the implementation uses repeated forward searches; and to + * provide for overlap checking between backwards matches on different + * text lines. */ + #define LOTS_OF_MATCHES 20 int matchNum = LOTS_OF_MATCHES; int smArray[2 * LOTS_OF_MATCHES]; @@ -5134,76 +5184,81 @@ SearchCore(interp, searchSpecPtr, patObj) int *storeLength = smArray + LOTS_OF_MATCHES; int lastBackwardsLineMatch = -1; int lastBackwardsMatchOffset = -1; - - /* These two items are for exact searches only */ - CONST char *pattern = NULL; - int firstNewLine = -1; if (searchSpecPtr->exact) { /* - * Convert the pattern to lower-case if we're supposed to ignore - * case. + * Convert the pattern to lower-case if we're supposed to ignore case. */ + if (searchSpecPtr->noCase) { patObj = Tcl_DuplicateObj(patObj); + /* - * This can change the length of the string behind the - * object's back, so ensure it is correctly synchronised. + * This can change the length of the string behind the object's + * back, so ensure it is correctly synchronised. */ + Tcl_SetObjLength(patObj, Tcl_UtfToLower(Tcl_GetString(patObj))); } } else { /* - * Compile the regular expression. We want '^$' to match after and + * Compile the regular expression. We want '^$' to match after and * before \n respectively, so use the TCL_REG_NLANCH flag. */ + regexp = Tcl_GetRegExpFromObj(interp, patObj, (searchSpecPtr->noCase ? TCL_REG_NOCASE : 0) | (searchSpecPtr->noLineStop ? 0 : TCL_REG_NLSTOP) - | TCL_REG_ADVANCED | TCL_REG_CANMATCH | TCL_REG_NLANCH); + | TCL_REG_ADVANCED | TCL_REG_CANMATCH | TCL_REG_NLANCH); if (regexp == NULL) { return TCL_ERROR; } } /* - * For exact strings, we want to know where the first newline is, - * and we will also use this as a flag to test whether it is even - * possible to match the pattern on a single line. If not we - * will have to search across multiple lines. + * For exact strings, we want to know where the first newline is, and we + * will also use this as a flag to test whether it is even possible to + * match the pattern on a single line. If not we will have to search + * across multiple lines. */ + if (searchSpecPtr->exact) { CONST char *nl; /* - * We only need to set the matchLength once for exact searches, - * and we do it here. It is also used below as the actual - * pattern length, so it has dual purpose. + * We only need to set the matchLength once for exact searches, and we + * do it here. It is also used below as the actual pattern length, so + * it has dual purpose. */ + pattern = Tcl_GetStringFromObj(patObj, &matchLength); nl = strchr(pattern, '\n'); + /* - * If there is no newline, or it is the very end of the string, - * then we don't need any special treatment, since single-line - * matching will work fine. + * If there is no newline, or it is the very end of the string, then + * we don't need any special treatment, since single-line matching + * will work fine. */ + if (nl != NULL && nl[1] != '\0') { firstNewLine = (nl - pattern); } } else { - matchLength = 0; /* Only needed to prevent compiler warnings. */ + matchLength = 0; /* Only needed to prevent compiler warnings. */ } /* - * Keep a reference here, so that we can be sure the object - * doesn't disappear behind our backs and invalidate its - * contents which we are using. + * Keep a reference here, so that we can be sure the object doesn't + * disappear behind our backs and invalidate its contents which we are + * using. */ + Tcl_IncrRefCount(patObj); /* - * For building up the current line being checked + * For building up the current line being checked. */ + theLine = Tcl_NewObj(); Tcl_IncrRefCount(theLine); @@ -5211,40 +5266,41 @@ SearchCore(interp, searchSpecPtr, patObj) ClientData lineInfo; int linesSearched = 1; int extraLinesSearched = 0; - + if (lineNum >= searchSpecPtr->numLines) { /* * Don't search the dummy last line of the text. */ + goto nextLine; } /* - * Extract the text from the line, storing its length in - * 'lastOffset' (in bytes if exact, chars if regexp), since - * obviously the length is the maximum offset at which - * it is possible to find something on this line, which is - * what 'lastOffset' represents. + * Extract the text from the line, storing its length in 'lastOffset' + * (in bytes if exact, chars if regexp), since obviously the length is + * the maximum offset at which it is possible to find something on + * this line, which is what 'lastOffset' represents. */ - lineInfo = (*searchSpecPtr->addLineProc)(lineNum, - searchSpecPtr, theLine, &lastOffset, &linesSearched); + lineInfo = (*searchSpecPtr->addLineProc)(lineNum, searchSpecPtr, + theLine, &lastOffset, &linesSearched); if (lineInfo == NULL) { - /* - * This should not happen, since 'lineNum' should be valid - * in the call above. However, let's try to be flexible and - * not cause a crash below. + /* + * This should not happen, since 'lineNum' should be valid in the + * call above. However, let's try to be flexible and not cause a + * crash below. */ + goto nextLine; } - + if (lineNum == searchSpecPtr->stopLine && searchSpecPtr->backwards) { firstOffset = searchSpecPtr->stopOffset; } else { firstOffset = 0; } - + if (alreadySearchOffset != -1) { if (searchSpecPtr->backwards) { if (alreadySearchOffset < lastOffset) { @@ -5257,18 +5313,19 @@ SearchCore(interp, searchSpecPtr, patObj) } alreadySearchOffset = -1; } - + if (lineNum == searchSpecPtr->startLine) { /* - * The starting line is tricky: the first time we see it - * we check one part of the line, and the second pass through - * we check the other part of the line. + * The starting line is tricky: the first time we see it we check + * one part of the line, and the second pass through we check the + * other part of the line. */ + passes++; if ((passes == 1) ^ searchSpecPtr->backwards) { /* - * Forward search and first pass, or backward - * search and second pass. + * Forward search and first pass, or backward search and + * second pass. * * Only use the last part of the line. */ @@ -5292,11 +5349,11 @@ SearchCore(interp, searchSpecPtr, patObj) } /* - * Check for matches within the current line 'lineNum'. If so, - * and if we're searching backwards or for all matches, repeat - * the search until we find the last match in the line. The - * 'lastOffset' is one beyond the last position in the line at - * which a match is allowed to begin. + * Check for matches within the current line 'lineNum'. If so, and if + * we're searching backwards or for all matches, repeat the search + * until we find the last match in the line. The 'lastOffset' is one + * beyond the last position in the line at which a match is allowed to + * begin. */ matchOffset = -1; @@ -5311,22 +5368,29 @@ SearchCore(interp, searchSpecPtr, patObj) int lastFullLine = lastOffset; if (firstNewLine == -1) { - if (searchSpecPtr->strictLimits - && (firstOffset + matchLength > lastOffset)) { - /* Not enough characters to match. */ - break; + if (searchSpecPtr->strictLimits + && (firstOffset + matchLength > lastOffset)) { + /* + * Not enough characters to match. + */ + + break; } - /* - * Single line matching. We want to scan forwards - * or backwards as appropriate. + + /* + * Single line matching. We want to scan forwards or + * backwards as appropriate. */ + if (searchSpecPtr->backwards) { - /* - * Search back either from the previous match or - * from 'startOfLine + lastOffset - 1' until we - * find a match. + /* + * Search back either from the previous match or from + * 'startOfLine + lastOffset - 1' until we find a + * match. */ + CONST char c = pattern[0]; + if (alreadySearchOffset != -1) { p = startOfLine + alreadySearchOffset; alreadySearchOffset = -1; @@ -5345,41 +5409,49 @@ SearchCore(interp, searchSpecPtr, patObj) p = strstr(startOfLine + firstOffset, pattern); } if (p == NULL) { - /* - * Single line match failed. + /* + * Single line match failed. */ - break; + + break; } } else if (firstNewLine >= (lastOffset - firstOffset)) { - /* - * Multi-line match, but not enough characters to - * match. + /* + * Multi-line match, but not enough characters to match. */ + break; } else { - /* - * Multi-line match has only one possible match - * position, because we know where the '\n' is. + /* + * Multi-line match has only one possible match position, + * because we know where the '\n' is. */ + p = startOfLine + lastOffset - firstNewLine - 1; if (strncmp(p, pattern, (unsigned)(firstNewLine + 1))) { - /* No match */ + /* + * No match. + */ break; } else { int extraLines = 1; - /* + + /* * If we find a match that overlaps more than one - * line, we will use this value to determine the - * first allowed starting offset for the following - * search (to avoid overlapping results). + * line, we will use this value to determine the first + * allowed starting offset for the following search + * (to avoid overlapping results). */ + int lastTotal = lastOffset; int skipFirst = lastOffset - firstNewLine -1; + /* - * We may be able to match if given more text. - * The following 'while' block handles multi-line - * exact searches. + * We may be able to match if given more text. The + * following 'while' block handles multi-line exact + * searches. */ + while (1) { lastFullLine = lastTotal; @@ -5389,9 +5461,10 @@ SearchCore(interp, searchSpecPtr, patObj) } /* - * Only add the line if we haven't already - * done so already. + * Only add the line if we haven't already done so + * already. */ + if (extraLines > maxExtraLines) { if ((*searchSpecPtr->addLineProc)(lineNum + extraLines, searchSpecPtr, theLine, @@ -5407,64 +5480,80 @@ SearchCore(interp, searchSpecPtr, patObj) startOfLine = Tcl_GetString(theLine); p = startOfLine + skipFirst; + /* - * Use the fact that 'matchLength = patLength' - * for exact searches + * Use the fact that 'matchLength = patLength' for + * exact searches. */ + if ((lastTotal - skipFirst) >= matchLength) { - /* - * We now have enough text to match, so - * we make a final test and break - * whatever the result - */ - if (strncmp(p, pattern, (unsigned)matchLength)) { + /* + * We now have enough text to match, so we + * make a final test and break whatever the + * result. + */ + + if (strncmp(p,pattern,(unsigned)matchLength)) { p = NULL; } break; } else { /* - * Not enough text yet, but check the prefix + * Not enough text yet, but check the prefix. */ + if (strncmp(p, pattern, (unsigned)(lastTotal - skipFirst))) { p = NULL; break; } + /* - * The prefix matches, so keep looking + * The prefix matches, so keep looking. */ } extraLines++; } /* * If we reach here, with p != NULL, we've found a - * multi-line match, else we started a multi-match - * but didn't finish it off, so we go to the next line. + * multi-line match, else we started a multi-match but + * didn't finish it off, so we go to the next line. */ + if (p == NULL) { break; } - /* We've found a multi-line match */ + + /* + * We've found a multi-line match. + */ + extraLinesSearched = extraLines - 1; } } - backwardsMatch: + + backwardsMatch: if ((p - startOfLine) >= lastOffset) { break; } + /* - * Remember the match + * Remember the match. */ + matchOffset = p - startOfLine; if (searchSpecPtr->all && - !(*searchSpecPtr->foundMatchProc)(lineNum, searchSpecPtr, - lineInfo, theLine, matchOffset, matchLength)) { + !(*searchSpecPtr->foundMatchProc)(lineNum, + searchSpecPtr, lineInfo, theLine, matchOffset, + matchLength)) { /* * We reached the end of the search */ + goto searchDone; } + if (!searchSpecPtr->overlap) { if (searchSpecPtr->backwards) { alreadySearchOffset = p - startOfLine; @@ -5476,18 +5565,20 @@ SearchCore(interp, searchSpecPtr, patObj) } else { firstOffset = p - startOfLine + matchLength; if (firstOffset >= lastOffset) { - /* + /* * Now, we have to be careful not to find * overlapping matches either on the same or - * following lines. Assume that if we did find - * something, it goes until the last extra line - * we added. - * - * We can break out of the loop, since we know - * no more will be found. + * following lines. Assume that if we did find + * something, it goes until the last extra line we + * added. + * + * We can break out of the loop, since we know no + * more will be found. */ + if (!searchSpecPtr->backwards) { - alreadySearchOffset = firstOffset - lastFullLine; + alreadySearchOffset = + firstOffset - lastFullLine; break; } } @@ -5499,8 +5590,8 @@ SearchCore(interp, searchSpecPtr, patObj) break; } } else { - firstOffset = p - startOfLine - + Tcl_UtfToUniChar(startOfLine + matchOffset, &ch); + firstOffset = p - startOfLine + + Tcl_UtfToUniChar(startOfLine+matchOffset, &ch); } } } while (searchSpecPtr->all); @@ -5510,12 +5601,12 @@ SearchCore(interp, searchSpecPtr, patObj) int maxExtraLines = 0; int matches = 0; int lastNonOverlap = -1; - + do { Tcl_RegExpInfo info; int match; int lastFullLine = lastOffset; - + match = Tcl_RegExpExecObj(interp, regexp, theLine, firstOffset, 1, ((firstOffset > 0) ? TCL_REG_NOTBOL : 0)); if (match < 0) { @@ -5524,54 +5615,66 @@ SearchCore(interp, searchSpecPtr, patObj) } Tcl_RegExpGetInfo(regexp, &info); - /* - * If we don't have a match, or if we do, but it - * extends to the end of the line, we must try to - * add more lines to get a full greedy match. + /* + * If we don't have a match, or if we do, but it extends to + * the end of the line, we must try to add more lines to get a + * full greedy match. */ - if (!match - || ((info.extendStart == info.matches[0].start) - && (info.matches[0].end == (lastOffset - firstOffset)))) { + + if (!match || + ((info.extendStart == info.matches[0].start) + && (info.matches[0].end == lastOffset-firstOffset))) { int extraLines = 0; int prevFullLine; - /* - * If we find a match that overlaps more than one - * line, we will use this value to determine the - * first allowed starting offset for the following - * search (to avoid overlapping results). + + /* + * If we find a match that overlaps more than one line, we + * will use this value to determine the first allowed + * starting offset for the following search (to avoid + * overlapping results). */ + int lastTotal = lastOffset; - + if ((lastBackwardsLineMatch != -1) - && (lastBackwardsLineMatch == (lineNum + 1))) { + && (lastBackwardsLineMatch == (lineNum + 1))) { lastNonOverlap = lastTotal; } if (info.extendStart < 0) { - /* No multi-line match is possible */ + /* + * No multi-line match is possible. + */ + break; } /* - * We may be able to match if given more text. - * The following 'while' block handles multi-line - * regexp searches. + * We may be able to match if given more text. The + * following 'while' block handles multi-line regexp + * searches. */ + while (1) { prevFullLine = lastTotal; + /* * Move firstOffset to first possible start */ - if (!match) firstOffset += info.extendStart; + + if (!match) { + firstOffset += info.extendStart; + } if (firstOffset >= lastOffset) { /* - * We're being told that the only possible - * new match is starting after the end of - * the line. But, that is the next line which - * we will handle when we look at that line. + * We're being told that the only possible new + * match is starting after the end of the line. + * But, that is the next line which we will handle + * when we look at that line. */ + if (!match && !searchSpecPtr->backwards - && (firstOffset == 0)) { + && (firstOffset == 0)) { extraLinesSearched = extraLines; } break; @@ -5580,128 +5683,145 @@ SearchCore(interp, searchSpecPtr, patObj) if (lineNum + extraLines >= searchSpecPtr->numLines) { break; } + /* - * Add next line, provided we haven't already done so + * Add next line, provided we haven't already done so. */ + if (extraLines > maxExtraLines) { if ((*searchSpecPtr->addLineProc)(lineNum + extraLines, searchSpecPtr, theLine, &lastTotal, &extraLines) == NULL) { /* - * There are no more acceptable lines, so - * we can say we have searched all of these + * There are no more acceptable lines, so we + * can say we have searched all of these. */ + if (!match && !searchSpecPtr->backwards) { extraLinesSearched = extraLines; } break; } + maxExtraLines = extraLines; if ((lastBackwardsLineMatch != -1) - && (lastBackwardsLineMatch + && (lastBackwardsLineMatch == (lineNum + extraLines + 1))) { lastNonOverlap = lastTotal; } } match = Tcl_RegExpExecObj(interp, regexp, theLine, - firstOffset, 1, - ((firstOffset > 0) ? TCL_REG_NOTBOL : 0)); + firstOffset, 1, + ((firstOffset > 0) ? TCL_REG_NOTBOL : 0)); if (match < 0) { code = TCL_ERROR; goto searchDone; } Tcl_RegExpGetInfo(regexp, &info); - /* + /* * Unfortunately there are bugs in Tcl's regexp - * library, which tells us that info.extendStart - * is zero when it should not be (should be -1), - * which makes our task a bit more complicated - * here. We check if there was a match, and the - * end of the match leaves an entire extra line - * unmatched, then we stop searching. Clearly it - * still might sometimes be possible to add more - * text and match again, but Tcl's regexp library - * doesn't tell us that. - * - * This means we often add and search one more - * line than might be necessary if Tcl were able - * to give us a correct value of info.extendStart - * under all circumstances. - */ - if ((match && ((firstOffset + info.matches[0].end) - != lastTotal) - && ((firstOffset + info.matches[0].end) - < prevFullLine)) - || info.extendStart < 0) { + * library, which tells us that info.extendStart is + * zero when it should not be (should be -1), which + * makes our task a bit more complicated here. We + * check if there was a match, and the end of the + * match leaves an entire extra line unmatched, then + * we stop searching. Clearly it still might sometimes + * be possible to add more text and match again, but + * Tcl's regexp library doesn't tell us that. + * + * This means we often add and search one more line + * than might be necessary if Tcl were able to give us + * a correct value of info.extendStart under all + * circumstances. + */ + + if ((match && + firstOffset+info.matches[0].end != lastTotal && + firstOffset+info.matches[0].end < prevFullLine) + || info.extendStart < 0) { break; } + /* - * If there is a match, but that match starts - * after the end of the first line, then we'll - * handle that next time around, when we're - * actually looking at that line. + * If there is a match, but that match starts after + * the end of the first line, then we'll handle that + * next time around, when we're actually looking at + * that line. */ + if (match && (info.matches[0].start >= lastOffset)) { break; } - if (match && ((firstOffset + info.matches[0].end) - >= prevFullLine)) { + if (match && ((firstOffset + info.matches[0].end) + >= prevFullLine)) { extraLinesSearched = extraLines - 1; lastFullLine = prevFullLine; } + /* - * The prefix matches, so keep looking + * The prefix matches, so keep looking. */ + extraLines++; } + /* * If we reach here with 'match == 1', we've found a * multi-line match, which we will record in the code - * which follows directly else we started a - * multi-line match but didn't finish it off, so we - * go to the next line. + * which follows directly else we started a multi-line + * match but didn't finish it off, so we go to the next + * line. */ + if (!match) { - /* + /* * Here is where we could perform an optimisation, - * since we have already retrieved the contents of - * the next line (perhaps many more), so we shouldn't - * really throw it all away and start again. This + * since we have already retrieved the contents of the + * next line (perhaps many more), so we shouldn't + * really throw it all away and start again. This * could be particularly important for complex regexp * searches. - * + * * This 'break' will take us to just before the * 'nextLine:' below. */ + break; } if (lastBackwardsLineMatch != -1) { - if ((lineNum + linesSearched + extraLinesSearched) - == lastBackwardsLineMatch) { - /* Possible overlap or inclusion */ - int thisOffset = firstOffset + info.matches[0].end - - info.matches[0].start; - + if ((lineNum + linesSearched + extraLinesSearched) + == lastBackwardsLineMatch) { + /* + * Possible overlap or inclusion. + */ + + int thisOffset = firstOffset + info.matches[0].end + - info.matches[0].start; + if (lastNonOverlap != -1) { - /* Possible overlap or enclosure */ - if ((thisOffset - lastNonOverlap) - >= (lastBackwardsMatchOffset - + matchLength)) { - /* + /* + * Possible overlap or enclosure. + */ + + if (thisOffset-lastNonOverlap >= + lastBackwardsMatchOffset+matchLength) { + /* * Totally encloses previous match, so - * forget the previous match + * forget the previous match. */ + lastBackwardsLineMatch = -1; - } else if ((thisOffset - lastNonOverlap) - > lastBackwardsMatchOffset) { - /* - * Overlap. Previous match is ok, and - * the current match is only ok if - * we are searching with -overlap. + } else if ((thisOffset - lastNonOverlap) + > lastBackwardsMatchOffset) { + /* + * Overlap. Previous match is ok, and the + * current match is only ok if we are + * searching with -overlap. */ + if (searchSpecPtr->overlap) { goto recordBackwardsMatch; } else { @@ -5709,83 +5829,95 @@ SearchCore(interp, searchSpecPtr, patObj) break; } } else { - /* - * No overlap, although the same - * line was reached. + /* + * No overlap, although the same line was + * reached. */ + goto recordBackwardsMatch; } } else { - /* No overlap */ + /* + * No overlap. + */ + goto recordBackwardsMatch; } - } else if (lineNum + linesSearched + extraLinesSearched - < lastBackwardsLineMatch) { - /* No overlap */ + } else if (lineNum+linesSearched+extraLinesSearched + < lastBackwardsLineMatch) { + /* + * No overlap. + */ + goto recordBackwardsMatch; } else { - /* Totally enclosed */ + /* + * Totally enclosed. + */ + lastBackwardsLineMatch = -1; } } } else { - /* Matched in a single line */ + /* + * Matched in a single line. + */ + if (lastBackwardsLineMatch != -1) { - recordBackwardsMatch: - (*searchSpecPtr->foundMatchProc)(lastBackwardsLineMatch, - searchSpecPtr, NULL, NULL, - lastBackwardsMatchOffset, matchLength); + recordBackwardsMatch: + (*searchSpecPtr->foundMatchProc)( + lastBackwardsLineMatch, searchSpecPtr, NULL, + NULL, lastBackwardsMatchOffset, matchLength); lastBackwardsLineMatch = -1; if (!searchSpecPtr->all) { goto searchDone; } } } - + firstOffset += info.matches[0].start; if (firstOffset >= lastOffset) { break; } /* - * Update our local variables with the match, if we - * haven't yet found anything, or if we're doing '-all' - * or '-backwards' _and_ this match isn't fully enclosed - * in the previous match. + * Update our local variables with the match, if we haven't + * yet found anything, or if we're doing '-all' or + * '-backwards' _and_ this match isn't fully enclosed in the + * previous match. */ - - if (matchOffset == -1 || - ((searchSpecPtr->all || searchSpecPtr->backwards) - && ((firstOffset < matchOffset) - || ((firstOffset + info.matches[0].end - - info.matches[0].start) - > (matchOffset + matchLength)) - ) - ) - ) { + + if (matchOffset == -1 || + ((searchSpecPtr->all || searchSpecPtr->backwards) + && ((firstOffset < matchOffset) + || ((firstOffset + info.matches[0].end + - info.matches[0].start) + > (matchOffset + matchLength))))) { matchOffset = firstOffset; matchLength = info.matches[0].end - info.matches[0].start; if (searchSpecPtr->backwards) { - /* - * To get backwards searches in the correct - * order, we must store them away here. + /* + * To get backwards searches in the correct order, we + * must store them away here. */ + if (matches == matchNum) { - /* - * We've run out of space in our normal - * store, so we must allocate space for - * these backwards matches on the heap. + /* + * We've run out of space in our normal store, so + * we must allocate space for these backwards + * matches on the heap. */ - int *newArray; - newArray = (int*) ckalloc(4*matchNum *sizeof(int)); + + int *newArray = (int *) + ckalloc(4 * matchNum * sizeof(int)); memcpy(newArray, storeMatch, matchNum*sizeof(int)); - memcpy(newArray + 2*matchNum, - storeLength, matchNum*sizeof(int)); + memcpy(newArray + 2*matchNum, storeLength, + matchNum * sizeof(int)); if (storeMatch != smArray) { - ckfree((char*)storeMatch); + ckfree((char *) storeMatch); } matchNum *= 2; storeMatch = newArray; @@ -5795,93 +5927,105 @@ SearchCore(interp, searchSpecPtr, patObj) storeLength[matches] = matchLength; matches++; } else { - /* - * Now actually record the match, but only if we - * are doing an '-all' search. + /* + * Now actually record the match, but only if we are + * doing an '-all' search. */ + if (searchSpecPtr->all && - !(*searchSpecPtr->foundMatchProc)(lineNum, - searchSpecPtr, lineInfo, theLine, matchOffset, - matchLength)) { + !(*searchSpecPtr->foundMatchProc)(lineNum, + searchSpecPtr, lineInfo, theLine, matchOffset, + matchLength)) { /* * We reached the end of the search */ + goto searchDone; } } + /* - * For forward matches, unless we allow overlaps, we - * move this on by the length of the current match so - * that we explicitly disallow overlapping matches. + * For forward matches, unless we allow overlaps, we move + * this on by the length of the current match so that we + * explicitly disallow overlapping matches. */ - if (matchLength > 0 && !searchSpecPtr->overlap - && !searchSpecPtr->backwards) { + + if (matchLength > 0 && !searchSpecPtr->overlap + && !searchSpecPtr->backwards) { firstOffset += matchLength; if (firstOffset >= lastOffset) { - /* + /* * Now, we have to be careful not to find * overlapping matches either on the same or - * following lines. Assume that if we did find - * something, it goes until the last extra line - * we added. - * - * We can break out of the loop, since we know - * no more will be found. + * following lines. Assume that if we did find + * something, it goes until the last extra line we + * added. + * + * We can break out of the loop, since we know no + * more will be found. */ + alreadySearchOffset = firstOffset - lastFullLine; break; } - /* We'll add this on again just below */ + + /* + * We'll add this on again just below. + */ + firstOffset --; } } /* - * Move the starting point on, in case we are doing - * repeated or backwards searches (for the latter, we - * actually do repeated forward searches). + * Move the starting point on, in case we are doing repeated + * or backwards searches (for the latter, we actually do + * repeated forward searches). */ + firstOffset++; } while (searchSpecPtr->backwards || searchSpecPtr->all); if (matches > 0) { - /* + /* * Now we have all the matches in our array, but not stored * with 'foundMatchProc' yet. */ + matches--; matchOffset = storeMatch[matches]; matchLength = storeLength[matches]; while (--matches >= 0) { if (lineNum == searchSpecPtr->stopLine) { - /* - * It appears as if a condition like - * 'if (storeMatch[matches] - * < searchSpecPtr->stopOffset) break;' - * - * might be needed here, but no test case - * has been found which would exercise such - * a problem. + /* + * It appears as if a condition like: + * + * if (storeMatch[matches]<searchSpecPtr->stopOffset) + * break; + * + * might be needed here, but no test case has been + * found which would exercise such a problem. */ } - if (storeMatch[matches] + storeLength[matches] - >= matchOffset + matchLength) { - /* - * The new match totally encloses the previous - * one, so we overwrite the previous one. + if (storeMatch[matches] + storeLength[matches] + >= matchOffset + matchLength) { + /* + * The new match totally encloses the previous one, so + * we overwrite the previous one. */ + matchOffset = storeMatch[matches]; matchLength = storeLength[matches]; continue; } if (!searchSpecPtr->overlap) { - if (storeMatch[matches] + storeLength[matches] - > matchOffset) { + if (storeMatch[matches] + storeLength[matches] + > matchOffset) { continue; } } (*searchSpecPtr->foundMatchProc)(lineNum, searchSpecPtr, - lineInfo, theLine, matchOffset, matchLength); + lineInfo, theLine, matchOffset, matchLength); if (!searchSpecPtr->all) { goto searchDone; } @@ -5889,13 +6033,14 @@ SearchCore(interp, searchSpecPtr, patObj) matchLength = storeLength[matches]; } if (searchSpecPtr->all && matches > 0) { - /* - * We only need to do this for the '-all' case, - * because just below we will call the - * foundMatchProc for the non-all case + /* + * We only need to do this for the '-all' case, because + * just below we will call the foundMatchProc for the + * non-all case. */ + (*searchSpecPtr->foundMatchProc)(lineNum, searchSpecPtr, - lineInfo, theLine, matchOffset, matchLength); + lineInfo, theLine, matchOffset, matchLength); } else { lastBackwardsLineMatch = lineNum; lastBackwardsMatchOffset = matchOffset; @@ -5904,18 +6049,17 @@ SearchCore(interp, searchSpecPtr, patObj) } /* - * If the 'all' flag is set, we will already have stored all - * matches, so we just proceed to the next line. + * If the 'all' flag is set, we will already have stored all matches, + * so we just proceed to the next line. * - * If not, and there is a match we need to store that information - * and we are done. + * If not, and there is a match we need to store that information and + * we are done. */ - if ((lastBackwardsLineMatch == -1) - && (matchOffset >= 0) - && !searchSpecPtr->all) { - (*searchSpecPtr->foundMatchProc)(lineNum, searchSpecPtr, - lineInfo, theLine, matchOffset, matchLength); + if ((lastBackwardsLineMatch == -1) && (matchOffset >= 0) + && !searchSpecPtr->all) { + (*searchSpecPtr->foundMatchProc)(lineNum, searchSpecPtr, lineInfo, + theLine, matchOffset, matchLength); goto searchDone; } @@ -5923,13 +6067,14 @@ SearchCore(interp, searchSpecPtr, patObj) * Go to the next (or previous) line; */ - nextLine: - linesSearched += extraLinesSearched; - + nextLine: + linesSearched += extraLinesSearched; + while (linesSearched-- > 0) { /* * If we have just completed the 'stopLine', we are done */ + if (lineNum == searchSpecPtr->stopLine) { goto searchDone; } @@ -5937,12 +6082,12 @@ SearchCore(interp, searchSpecPtr, patObj) if (searchSpecPtr->backwards) { lineNum--; - if (lastBackwardsLineMatch != -1 - && ((lineNum < 0) || (lineNum + 2 < lastBackwardsLineMatch))) { - (*searchSpecPtr->foundMatchProc)(lastBackwardsLineMatch, - searchSpecPtr, NULL, NULL, - lastBackwardsMatchOffset, - matchLength); + if (lastBackwardsLineMatch != -1 + && ((lineNum < 0) + || (lineNum + 2 < lastBackwardsLineMatch))) { + (*searchSpecPtr->foundMatchProc)(lastBackwardsLineMatch, + searchSpecPtr, NULL, NULL, + lastBackwardsMatchOffset, matchLength); lastBackwardsLineMatch = -1; if (!searchSpecPtr->all) { goto searchDone; @@ -5953,15 +6098,15 @@ SearchCore(interp, searchSpecPtr, patObj) lineNum = searchSpecPtr->numLines-1; } if (!searchSpecPtr->exact) { - /* - * The 'exact' search loops above are designed to - * give us an accurate picture of the number of lines - * which we can skip here. For 'regexp' searches, on - * the other hand, which can match potentially variable - * lengths, we cannot skip multiple lines when searching - * backwards. Therefore we only allow one line to be - * skipped here. + /* + * The 'exact' search loops above are designed to give us + * an accurate picture of the number of lines which we can + * skip here. For 'regexp' searches, on the other hand, + * which can match potentially variable lengths, we cannot + * skip multiple lines when searching backwards. Therefore + * we only allow one line to be skipped here. */ + break; } } else { @@ -5971,11 +6116,12 @@ SearchCore(interp, searchSpecPtr, patObj) } } if (lineNum == searchSpecPtr->startLine && linesSearched > 0) { - /* - * We've just searched all the way round and have - * gone right through the start line without finding - * anything in the last attempt. + /* + * We've just searched all the way round and have gone right + * through the start line without finding anything in the last + * attempt. */ + break; } } @@ -5986,18 +6132,20 @@ SearchCore(interp, searchSpecPtr, patObj) if (lastBackwardsLineMatch != -1) { (*searchSpecPtr->foundMatchProc)(lastBackwardsLineMatch, searchSpecPtr, - NULL, NULL, lastBackwardsMatchOffset, matchLength); + NULL, NULL, lastBackwardsMatchOffset, matchLength); } - + /* * Free up the cached line and pattern */ + Tcl_DecrRefCount(theLine); Tcl_DecrRefCount(patObj); /* * Free up any extra space we allocated */ + if (storeMatch != smArray) { ckfree((char*)storeMatch); } @@ -6010,9 +6158,8 @@ SearchCore(interp, searchSpecPtr, patObj) * * GetLineStartEnd - * - * Converts an internal TkTextLine ptr into a Tcl string obj - * containing the line number. (Handler for the 'line' - * configuration option type) + * Converts an internal TkTextLine ptr into a Tcl string obj containing + * the line number. (Handler for the 'line' configuration option type.) * * Results: * Tcl_Obj containing the string representation of the line value. @@ -6045,16 +6192,15 @@ GetLineStartEnd(clientData, tkwin, recordPtr, internalOffset) * * SetLineStartEnd -- * - * Converts a Tcl_Obj representing a widget's (start or end) line - * into a TkTextLine* value. (Handler for the 'line' configuration - * option type) + * Converts a Tcl_Obj representing a widget's (start or end) line into a + * TkTextLine* value. (Handler for the 'line' configuration option type.) * * Results: * Standard Tcl result. * * Side effects: * May store the TkTextLine* value into the internal representation - * pointer. May change the pointer to the Tcl_Obj to NULL to indicate + * pointer. May change the pointer to the Tcl_Obj to NULL to indicate * that the specified string was empty and that is acceptable. * *---------------------------------------------------------------------- @@ -6067,28 +6213,29 @@ SetLineStartEnd(clientData, interp, tkwin, value, recordPtr, internalOffset, Tcl_Interp *interp; /* Current interp; may be used for errors. */ Tk_Window tkwin; /* Window for which option is being set. */ Tcl_Obj **value; /* Pointer to the pointer to the value object. - * We use a pointer to the pointer because - * we may need to return a value (NULL). */ + * We use a pointer to the pointer because we + * may need to return a value (NULL). */ char *recordPtr; /* Pointer to storage for the widget record. */ int internalOffset; /* Offset within *recordPtr at which the - internal value is to be stored. */ + * internal value is to be stored. */ char *oldInternalPtr; /* Pointer to storage for the old value. */ int flags; /* Flags for the option, set Tk_SetOptions. */ { TkTextLine *linePtr = NULL; char *internalPtr; TkText *textPtr = (TkText*)recordPtr; - + if (internalOffset >= 0) { internalPtr = recordPtr + internalOffset; } else { internalPtr = NULL; } - + if (flags & TK_OPTION_NULL_OK && ObjectIsEmpty(*value)) { *value = NULL; } else { int line; + if (Tcl_GetIntFromObj(interp, *value, &line) != TCL_OK) { return TCL_ERROR; } @@ -6100,15 +6247,15 @@ SetLineStartEnd(clientData, interp, tkwin, value, recordPtr, internalOffset, *((TkTextLine **) internalPtr) = linePtr; } return TCL_OK; -} +} /* *---------------------------------------------------------------------- * * RestoreLineStartEnd -- * - * Restore a line option value from a saved value. (Handler for - * the 'line' configuration option type) + * Restore a line option value from a saved value. (Handler for the + * 'line' configuration option type.) * * Results: * None. @@ -6134,12 +6281,11 @@ RestoreLineStartEnd(clientData, tkwin, internalPtr, oldInternalPtr) * * ObjectIsEmpty -- * - * This procedure tests whether the string value of an object is - * empty. + * This function tests whether the string value of an object is empty. * * Results: - * The return value is 1 if the string value of objPtr has length - * zero, and 0 otherwise. + * The return value is 1 if the string value of objPtr has length zero, + * and 0 otherwise. * * Side effects: * May cause object shimmering, since this function can force a @@ -6150,7 +6296,7 @@ RestoreLineStartEnd(clientData, tkwin, internalPtr, oldInternalPtr) static int ObjectIsEmpty(objPtr) - Tcl_Obj *objPtr; /* Object to test. May be NULL. */ + Tcl_Obj *objPtr; /* Object to test. May be NULL. */ { int length; @@ -6163,3 +6309,11 @@ ObjectIsEmpty(objPtr) Tcl_GetStringFromObj(objPtr, &length); return (length == 0); } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |