Home | History | Annotate | Line # | Download | only in src
      1 /*
      2 
      3 Copyright 1989, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24 
     25 */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include <config.h>
     29 #endif
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <unistd.h>
     33 #include <X11/Xos.h>		/* for select() and struct timeval */
     34 #include <ctype.h>
     35 #include <X11/IntrinsicP.h>
     36 #include <X11/StringDefs.h>
     37 #include <X11/Xatom.h>
     38 #include <X11/Xfuncs.h>
     39 #include <X11/Xutil.h>
     40 #include <X11/Xmu/Atoms.h>
     41 #include <X11/Xmu/Misc.h>
     42 #include <X11/Xmu/StdSel.h>
     43 #include <X11/Xaw/MultiSinkP.h>
     44 #include <X11/Xaw/MultiSrcP.h>
     45 #include <X11/Xaw/TextP.h>
     46 #include <X11/Xaw/TextSrcP.h>
     47 #include <X11/Xaw/XawImP.h>
     48 #include "Private.h"
     49 #include "XawI18n.h"
     50 
     51 #ifdef _WIN32
     52 #include <X11/Xwinsock.h>
     53 #endif
     54 
     55 #define SrcScan			XawTextSourceScan
     56 #define FindDist		XawTextSinkFindDistance
     57 #define FindPos			XawTextSinkFindPosition
     58 #define MULT(w)			(w->text.mult == 0 ? 4 :		\
     59 				 w->text.mult == 32767 ? -4 : w->text.mult)
     60 
     61 #define KILL_RING_APPEND	2
     62 #define KILL_RING_BEGIN		3
     63 #define KILL_RING_YANK		100
     64 #define KILL_RING_YANK_DONE	98
     65 
     66 #define XawTextActionMaxHexChars	100
     67 
     68 /*
     69  * Prototypes
     70  */
     71 static void _DeleteOrKill(TextWidget, XawTextPosition, XawTextPosition, Bool);
     72 static void _SelectionReceived(Widget, XtPointer, Atom*, Atom*, XtPointer,
     73 			       unsigned long*, int*);
     74 static void _LoseSelection(Widget, Atom*, char**, int*);
     75 static void AutoFill(TextWidget);
     76 static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
     77 				unsigned long*, int*);
     78 static void DeleteOrKill(TextWidget, XEvent*, XawTextScanDirection,
     79 			 XawTextScanType, Bool, Bool);
     80 static void EndAction(TextWidget);
     81 #ifndef OLDXAW
     82 static Bool BlankLine(Widget, XawTextPosition, int*);
     83 static int DoFormatText(TextWidget, XawTextPosition, Bool, int,
     84 			XawTextBlock*, XawTextPosition*, int, Bool);
     85 static int FormatText(TextWidget, XawTextPosition, Bool,
     86 		      XawTextPosition*, int);
     87 static Bool GetBlockBoundaries(TextWidget, XawTextPosition*, XawTextPosition*);
     88 #endif
     89 static int FormRegion(TextWidget, XawTextPosition, XawTextPosition,
     90 		      XawTextPosition*, int);
     91 static void GetSelection(Widget, Time, String*, Cardinal);
     92 static char *IfHexConvertHexElseReturnParam(const char*, int*);
     93 static void InsertNewCRs(TextWidget, XawTextPosition, XawTextPosition,
     94 			 XawTextPosition*, int);
     95 static int InsertNewLineAndBackupInternal(TextWidget);
     96 static int LocalInsertNewLine(TextWidget, XEvent*);
     97 static void LoseSelection(Widget, Atom*);
     98 static void ParameterError(Widget, String);
     99 static Bool MatchSelection(Atom, XawTextSelection*);
    100 static void ModifySelection(TextWidget, XEvent*, XawTextSelectionMode,
    101 			    XawTextSelectionAction, String*, Cardinal*);
    102 static void Move(TextWidget, XEvent*, XawTextScanDirection, XawTextScanType,
    103 		 Bool);
    104 static void NotePosition(TextWidget, XEvent*);
    105 static void StartAction(TextWidget, XEvent*);
    106 static XawTextPosition StripOutOldCRs(TextWidget, XawTextPosition,
    107 				      XawTextPosition, XawTextPosition*, int);
    108 #ifndef OLDXAW
    109 static Bool StripSpaces(TextWidget, XawTextPosition, XawTextPosition,
    110 			XawTextPosition*, int, XawTextBlock*);
    111 static Bool Tabify(TextWidget, XawTextPosition, XawTextPosition,
    112 		   XawTextPosition*, int, XawTextBlock*);
    113 static Bool Untabify(TextWidget, XawTextPosition, XawTextPosition,
    114 		     XawTextPosition*, int, XawTextBlock*);
    115 #endif
    116 
    117 /*
    118  * Actions
    119  */
    120 static void CapitalizeWord(Widget, XEvent*, String*, Cardinal*);
    121 static void DisplayCaret(Widget, XEvent*, String*, Cardinal*);
    122 static void Delete(Widget, XEvent*, String*, Cardinal*);
    123 static void DeleteBackwardChar(Widget, XEvent*, String*, Cardinal*);
    124 static void DeleteBackwardWord(Widget, XEvent*, String*, Cardinal*);
    125 static void DeleteCurrentSelection(Widget, XEvent*, String*, Cardinal*);
    126 static void DeleteForwardChar(Widget, XEvent*, String*, Cardinal*);
    127 static void DeleteForwardWord(Widget, XEvent*, String*, Cardinal*);
    128 static void DowncaseWord(Widget, XEvent*, String*, Cardinal*);
    129 static void ExtendAdjust(Widget, XEvent*, String*, Cardinal*);
    130 static void ExtendEnd(Widget, XEvent*, String*, Cardinal*);
    131 static void ExtendStart(Widget, XEvent*, String*, Cardinal*);
    132 static void FormParagraph(Widget, XEvent*, String*, Cardinal*);
    133 #ifndef OLDXAW
    134 static void Indent(Widget, XEvent*, String*, Cardinal*);
    135 #endif
    136 static void InsertChar(Widget, XEvent*, String*, Cardinal*);
    137 static void InsertNewLine(Widget, XEvent*, String*, Cardinal*);
    138 static void InsertNewLineAndBackup(Widget, XEvent*, String*, Cardinal*);
    139 static void InsertNewLineAndIndent(Widget, XEvent*, String*, Cardinal*);
    140 static void InsertSelection(Widget, XEvent*, String*, Cardinal*);
    141 static void InsertString(Widget, XEvent*, String*, Cardinal*);
    142 #ifndef OLDXAW
    143 static void KeyboardReset(Widget, XEvent*, String*, Cardinal*);
    144 #endif
    145 static void KillBackwardWord(Widget, XEvent*, String*, Cardinal*);
    146 static void KillCurrentSelection(Widget, XEvent*, String*, Cardinal*);
    147 static void KillForwardWord(Widget, XEvent*, String*, Cardinal*);
    148 #ifndef OLDXAW
    149 static void KillRingYank(Widget, XEvent*, String*, Cardinal*);
    150 #endif
    151 static void KillToEndOfLine(Widget, XEvent*, String*, Cardinal*);
    152 static void KillToEndOfParagraph(Widget, XEvent*, String*, Cardinal*);
    153 static void MoveBackwardChar(Widget, XEvent*, String*, Cardinal*);
    154 static void MoveBackwardWord(Widget, XEvent*, String*, Cardinal*);
    155 static void MoveBackwardParagraph(Widget, XEvent*, String*, Cardinal*);
    156 static void MoveBeginningOfFile(Widget, XEvent*, String*, Cardinal*);
    157 static void MoveEndOfFile(Widget, XEvent*, String*, Cardinal*);
    158 static void MoveForwardChar(Widget, XEvent*, String*, Cardinal*);
    159 static void MoveForwardWord(Widget, XEvent*, String*, Cardinal*);
    160 static void MoveForwardParagraph(Widget, XEvent*, String*, Cardinal*);
    161 static void MoveNextLine(Widget, XEvent*, String*, Cardinal*);
    162 static void MoveNextPage(Widget, XEvent*, String*, Cardinal*);
    163 static void MovePage(TextWidget, XEvent*, XawTextScanDirection);
    164 static void MovePreviousLine(Widget, XEvent*, String*, Cardinal*);
    165 static void MovePreviousPage(Widget, XEvent*, String*, Cardinal*);
    166 static void MoveLine(TextWidget, XEvent*, XawTextScanDirection);
    167 static void MoveToLineEnd(Widget, XEvent*, String*, Cardinal*);
    168 static void MoveToLineStart(Widget, XEvent*, String*, Cardinal*);
    169 static void Multiply(Widget, XEvent*, String*, Cardinal*);
    170 static void NoOp(Widget, XEvent*, String*, Cardinal*);
    171 #ifndef OLDXAW
    172 static void Numeric(Widget, XEvent*, String*, Cardinal*);
    173 #endif
    174 static void Reconnect(Widget, XEvent*, String*, Cardinal*);
    175 static void RedrawDisplay(Widget, XEvent*, String*, Cardinal*);
    176 static void Scroll(TextWidget, XEvent*, XawTextScanDirection);
    177 static void ScrollOneLineDown(Widget, XEvent*, String*, Cardinal*);
    178 static void ScrollOneLineUp(Widget, XEvent*, String*, Cardinal*);
    179 static void SelectAdjust(Widget, XEvent*, String*, Cardinal*);
    180 static void SelectAll(Widget, XEvent*, String*, Cardinal*);
    181 static void SelectEnd(Widget, XEvent*, String*, Cardinal*);
    182 static void SelectSave(Widget, XEvent*, String*, Cardinal*);
    183 static void SelectStart(Widget, XEvent*, String*, Cardinal*);
    184 static void SelectWord(Widget, XEvent*, String*, Cardinal*);
    185 static void SetKeyboardFocus(Widget, XEvent*, String*, Cardinal*);
    186 static void TextEnterWindow(Widget, XEvent*, String*, Cardinal*);
    187 static void TextFocusIn(Widget, XEvent*, String*, Cardinal*);
    188 static void TextFocusOut(Widget, XEvent*, String*, Cardinal*);
    189 static void TextLeaveWindow(Widget, XEvent*, String*, Cardinal*);
    190 static void TransposeCharacters(Widget, XEvent*, String*, Cardinal*);
    191 #ifndef OLDXAW
    192 static void ToggleOverwrite(Widget, XEvent*, String*, Cardinal*);
    193 static void Undo(Widget, XEvent*, String*, Cardinal*);
    194 #endif
    195 static void UpcaseWord(Widget, XEvent*, String*, Cardinal*);
    196 static void DestroyFocusCallback(Widget, XtPointer, XtPointer);
    197 
    198 /*
    199  * External
    200  */
    201 void _XawTextZapSelection(TextWidget, XEvent*, Bool);
    202 
    203 /*
    204  * Defined in TextPop.c
    205  */
    206 void _XawTextInsertFileAction(Widget, XEvent*, String*, Cardinal*);
    207 void _XawTextInsertFile(Widget, XEvent*, String*, Cardinal*);
    208 void _XawTextSearch(Widget, XEvent*, String*, Cardinal*);
    209 void _XawTextDoSearchAction(Widget, XEvent*, String*, Cardinal*);
    210 void _XawTextDoReplaceAction(Widget, XEvent*, String*, Cardinal*);
    211 void _XawTextSetField(Widget, XEvent*, String*, Cardinal*);
    212 void _XawTextPopdownSearchAction(Widget, XEvent*, String*, Cardinal*);
    213 
    214 /*
    215  * These are defined in Text.c
    216  */
    217 void _XawTextAlterSelection(TextWidget, XawTextSelectionMode,
    218 			    XawTextSelectionAction, String*, Cardinal*);
    219 void _XawTextClearAndCenterDisplay(TextWidget);
    220 void _XawTextExecuteUpdate(TextWidget);
    221 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
    222 void _XawTextPrepareToUpdate(TextWidget);
    223 int _XawTextReplace(TextWidget, XawTextPosition, XawTextPosition,
    224 			   XawTextBlock*);
    225 Atom *_XawTextSelectionList(TextWidget, String*, Cardinal);
    226 void _XawTextSetSelection(TextWidget, XawTextPosition, XawTextPosition,
    227 				 String*, Cardinal);
    228 void _XawTextVScroll(TextWidget, int);
    229 void XawTextScroll(TextWidget, int, int);
    230 void _XawTextSetLineAndColumnNumber(TextWidget, Bool);
    231 
    232 #ifndef OLDXAW
    233 /*
    234  * Defined in TextSrc.c
    235  */
    236 Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
    237 Bool _XawTextSrcToggleUndo(TextSrcObject);
    238 void _XawSourceSetUndoErase(TextSrcObject, int);
    239 void _XawSourceSetUndoMerge(TextSrcObject, Bool);
    240 #endif /* OLDXAW */
    241 
    242 /*
    243  * Initialization
    244  */
    245 #ifndef OLDXAW
    246 #define MAX_KILL_RINGS	1024
    247 XawTextKillRing *xaw_text_kill_ring;
    248 static XawTextKillRing kill_ring_prev, kill_ring_null = { &kill_ring_prev, NULL, 0, 0, 0 };
    249 static unsigned num_kill_rings;
    250 #endif
    251 
    252 /*
    253  * Implementation
    254  */
    255 static void
    256 ParameterError(Widget w, String param)
    257 {
    258     String params[2];
    259     Cardinal num_params = 2;
    260     params[0] = XtName(w);
    261     params[1] = param;
    262 
    263     XtAppWarningMsg(XtWidgetToApplicationContext(w),
    264 		    "parameterError", "textAction", "XawError",
    265 		    "Widget: %s Parameter: %s",
    266 		    params, &num_params);
    267     XBell(XtDisplay(w), 50);
    268 }
    269 
    270 static void
    271 StartAction(TextWidget ctx, XEvent *event)
    272 {
    273 #ifndef OLDXAW
    274     Cardinal i;
    275     TextSrcObject src = (TextSrcObject)ctx->text.source;
    276 
    277     for (i = 0; i < src->textSrc.num_text; i++)
    278 	_XawTextPrepareToUpdate((TextWidget)src->textSrc.text[i]);
    279     _XawSourceSetUndoMerge(src, False);
    280 #else
    281     _XawTextPrepareToUpdate(ctx);
    282 #endif
    283 
    284     if (event != NULL) {
    285 	switch (event->type) {
    286 	    case ButtonPress:
    287 	    case ButtonRelease:
    288 		ctx->text.time = event->xbutton.time;
    289 		break;
    290 	    case KeyPress:
    291 	    case KeyRelease:
    292 		ctx->text.time = event->xkey.time;
    293 		break;
    294 	    case MotionNotify:
    295 		ctx->text.time = event->xmotion.time;
    296 		break;
    297 	    case EnterNotify:
    298 	    case LeaveNotify:
    299 		ctx->text.time = event->xcrossing.time;
    300 	}
    301     }
    302 }
    303 
    304 static void
    305 NotePosition(TextWidget ctx, XEvent *event)
    306 {
    307     switch (event->type) {
    308 	case ButtonPress:
    309 	case ButtonRelease:
    310 	    ctx->text.ev_x = (Position)event->xbutton.x;
    311 	    ctx->text.ev_y = (Position)event->xbutton.y;
    312 	    break;
    313 	case KeyPress:
    314 	case KeyRelease: {
    315 	    XRectangle cursor;
    316 	    XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
    317 	    ctx->text.ev_x = (Position)(cursor.x + cursor.width / 2);
    318 	    ctx->text.ev_y = (Position)(cursor.y + cursor.height / 2);
    319 	}   break;
    320 	case MotionNotify:
    321 	    ctx->text.ev_x = (Position)(event->xmotion.x);
    322 	    ctx->text.ev_y = (Position)(event->xmotion.y);
    323 	    break;
    324 	case EnterNotify:
    325 	case LeaveNotify:
    326 	    ctx->text.ev_x = (Position)(event->xcrossing.x);
    327 	    ctx->text.ev_y = (Position)(event->xcrossing.y);
    328     }
    329 }
    330 
    331 static void
    332 EndAction(TextWidget ctx)
    333 {
    334 #ifndef OLDXAW
    335     Cardinal i;
    336     TextSrcObject src = (TextSrcObject)ctx->text.source;
    337 
    338     for (i = 0; i < src->textSrc.num_text; i++)
    339 	_XawTextExecuteUpdate((TextWidget)src->textSrc.text[i]);
    340 
    341     ctx->text.mult = 1;
    342     ctx->text.numeric = False;
    343     if (ctx->text.kill_ring) {
    344 	if (--ctx->text.kill_ring == KILL_RING_YANK_DONE) {
    345 	    if (ctx->text.kill_ring_ptr) {
    346 		--ctx->text.kill_ring_ptr->refcount;
    347 		ctx->text.kill_ring_ptr = NULL;
    348 	    }
    349 	}
    350     }
    351 #else
    352     ctx->text.mult = 1;
    353     _XawTextExecuteUpdate(ctx);
    354 #endif /* OLDXAW */
    355 }
    356 
    357 struct _SelectionList {
    358     String* params;
    359     Cardinal count;
    360     Time time;
    361     int asked;		/* which selection currently has been asked for:
    362 			   0 = UTF8_STRING, 1 = COMPOUND_TEXT, 2 = STRING */
    363     Atom selection;	/* selection atom (normally XA_PRIMARY) */
    364 };
    365 
    366 /*ARGSUSED*/
    367 static void
    368 _SelectionReceived(Widget w, XtPointer client_data, Atom *selection _X_UNUSED,
    369 		   Atom *type, XtPointer value, unsigned long *length,
    370 		   int *format _X_UNUSED)
    371 {
    372     Display *d = XtDisplay(w);
    373     TextWidget ctx = (TextWidget)w;
    374     XawTextBlock text;
    375 
    376     if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) {
    377 	struct _SelectionList* list = (struct _SelectionList*)client_data;
    378 
    379 	if (list != NULL) {
    380 	    if (list->asked == 0) {
    381 		/* If we just asked for XA_UTF8_STRING and got no response,
    382 		   we'll ask again, this time for XA_COMPOUND_TEXT. */
    383 		list->asked++;
    384 		XtGetSelectionValue(w, list->selection, XA_COMPOUND_TEXT(d),
    385 				    _SelectionReceived,
    386 				    (XtPointer)list, list->time);
    387 	    } else if (list->asked == 1) {
    388 		/* If we just asked for XA_COMPOUND_TEXT and got no response,
    389 		   we'll ask again, this time for XA_STRING. */
    390 		list->asked++;
    391 		XtGetSelectionValue(w, list->selection, XA_STRING,
    392 				    _SelectionReceived,
    393 				    (XtPointer)list, list->time);
    394 	    } else {
    395 		/* We tried all possible text targets in this param.
    396 		   Recurse on the tail of the params list. */
    397 		GetSelection(w, list->time, list->params, list->count);
    398 		XtFree(client_data);
    399 	    }
    400 	}
    401 	return;
    402     }
    403 
    404     StartAction(ctx, NULL);
    405     if (XawTextFormat(ctx, XawFmtWide)) {
    406 	wchar_t **wlist;
    407 	int count;
    408 	XTextProperty textprop = {
    409 	    .encoding = *type,
    410 	    .value = (unsigned char *)value,
    411 	    .nitems = strlen(value),
    412 	    .format = 8
    413 	};
    414 
    415 	if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
    416 	    !=	Success
    417 	    || count < 1) {
    418 	    XwcFreeStringList(wlist);
    419 
    420 	    /* Notify the user on strerr and in the insertion :) */
    421 	    fprintf(stderr, "Xaw Text Widget: An attempt was made to insert "
    422 		    "an illegal selection.\n");
    423 
    424 	    textprop.value = (unsigned char *)" >> ILLEGAL SELECTION << ";
    425 	    textprop.nitems = strlen((char *) textprop.value);
    426 	    if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
    427 		!=  Success
    428 		|| count < 1)
    429 		return;
    430 	}
    431 
    432 	XFree(value);
    433 	value = (XPointer)wlist[0];
    434 
    435 	*length = wcslen(wlist[0]);
    436 	XtFree((XtPointer)wlist);
    437 	text.format = XawFmtWide;
    438     }
    439     text.ptr = (char*)value;
    440     text.firstPos = 0;
    441     text.length = (int)*length;
    442     if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
    443 	XBell(XtDisplay(ctx), 0);
    444 	EndAction(ctx);
    445 	return;
    446     }
    447 
    448     ctx->text.from_left = -1;
    449     ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
    450 				  XawstPositions, XawsdRight, text.length, True);
    451 
    452     EndAction(ctx);
    453     XtFree(client_data);
    454     XFree(value);	/* the selection value should be freed with XFree */
    455 }
    456 
    457 static void
    458 GetSelection(Widget w, Time timev, String *params, Cardinal num_params)
    459 {
    460     Display *d = XtDisplay(w);
    461     TextWidget ctx = (TextWidget)w;
    462     Atom selection;
    463     int buffer;
    464 
    465     selection = XInternAtom(XtDisplay(w), *params, False);
    466     switch (selection) {
    467 	case XA_CUT_BUFFER0: buffer = 0; break;
    468 	case XA_CUT_BUFFER1: buffer = 1; break;
    469 	case XA_CUT_BUFFER2: buffer = 2; break;
    470 	case XA_CUT_BUFFER3: buffer = 3; break;
    471 	case XA_CUT_BUFFER4: buffer = 4; break;
    472 	case XA_CUT_BUFFER5: buffer = 5; break;
    473 	case XA_CUT_BUFFER6: buffer = 6; break;
    474 	case XA_CUT_BUFFER7: buffer = 7; break;
    475 	default:	     buffer = -1;
    476     }
    477     if (buffer >= 0) {
    478 	int nbytes;
    479 	unsigned long length;
    480 	int fmt8 = 8;
    481 	Atom type = XA_STRING;
    482 	char *line = XFetchBuffer(XtDisplay(w), &nbytes, buffer);
    483 
    484 	if ((length = (unsigned long)nbytes) != 0L)
    485 	    _SelectionReceived(w, NULL, &selection, &type, line, &length, &fmt8);
    486 	else if (num_params > 1)
    487 	    GetSelection(w, timev, params+1, num_params-1);
    488     }
    489     else {
    490 	struct _SelectionList* list;
    491 
    492 	if (--num_params) {
    493 	    list = XtNew(struct _SelectionList);
    494 	    list->params = params + 1;
    495 	    list->count = num_params;
    496 	    list->time = timev;
    497 	    list->asked = 0;
    498 	    list->selection = selection;
    499 	}
    500 	else
    501 	    list = NULL;
    502 	XtGetSelectionValue(w, selection, XawTextFormat(ctx, XawFmtWide) ?
    503 			    XA_UTF8_STRING(d) : XA_TEXT(d),
    504 			    _SelectionReceived, (XtPointer)list, timev);
    505     }
    506 }
    507 
    508 static void
    509 InsertSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
    510 {
    511     StartAction((TextWidget)w, event);	/* Get Time. */
    512     GetSelection(w, ((TextWidget)w)->text.time, params, *num_params);
    513     EndAction((TextWidget)w);
    514 }
    515 
    516 /*
    517  * Routines for Moving Around
    518  */
    519 static void
    520 Move(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
    521      XawTextScanType type, Bool include)
    522 {
    523     XawTextPosition insertPos;
    524     short mult = MULT(ctx);
    525 
    526     if (mult < 0) {
    527 	mult = (short)(-mult);
    528 	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
    529     }
    530 
    531     insertPos = SrcScan(ctx->text.source, ctx->text.insertPos,
    532 			type, dir, mult, (Boolean)include);
    533 
    534     StartAction(ctx, event);
    535 
    536     if (ctx->text.s.left != ctx->text.s.right)
    537 	XawTextUnsetSelection((Widget)ctx);
    538 
    539 #ifndef OLDXAW
    540     ctx->text.numeric = False;
    541 #endif
    542     ctx->text.mult = 1;
    543     ctx->text.showposition = True;
    544     ctx->text.from_left = -1;
    545     ctx->text.insertPos = insertPos;
    546     EndAction(ctx);
    547 }
    548 
    549 /*ARGSUSED*/
    550 static void
    551 MoveForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    552 {
    553     Move((TextWidget)w, event, XawsdRight, XawstPositions, True);
    554 }
    555 
    556 /*ARGSUSED*/
    557 static void
    558 MoveBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    559 {
    560     Move((TextWidget)w, event, XawsdLeft, XawstPositions, True);
    561 }
    562 
    563 static void
    564 MoveForwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
    565 {
    566     if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
    567 	Move((TextWidget)w, event, XawsdRight, XawstAlphaNumeric, False);
    568     else
    569 	Move((TextWidget)w, event, XawsdRight, XawstWhiteSpace, False);
    570 }
    571 
    572 static void
    573 MoveBackwardWord(Widget w, XEvent *event, String *p, Cardinal *n)
    574 {
    575     if (*n && (p[0][0] == 'A' || p[0][0] == 'a'))
    576 	Move((TextWidget)w, event, XawsdLeft, XawstAlphaNumeric, False);
    577     else
    578 	Move((TextWidget)w, event, XawsdLeft, XawstWhiteSpace, False);
    579 }
    580 
    581 static void
    582 MoveForwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
    583 {
    584     TextWidget ctx = (TextWidget)w;
    585     XawTextPosition position = ctx->text.insertPos;
    586     short mult = MULT(ctx);
    587 
    588     if (mult < 0) {
    589 	ctx->text.mult = (short)(-mult);
    590 	MoveBackwardParagraph(w, event, p, n);
    591 	return;
    592     }
    593 
    594     while (mult--) {
    595 	position = SrcScan(ctx->text.source, position,
    596 			   XawstEOL, XawsdRight, 1, False) - 1;
    597 
    598 	while (position == SrcScan(ctx->text.source, position,
    599 				   XawstEOL, XawsdRight, 1, False))
    600 	    if (++position > ctx->text.lastPos) {
    601 		mult = 0;
    602 		break;
    603 	    }
    604 
    605 	position = SrcScan(ctx->text.source, position,
    606 			   XawstParagraph, XawsdRight, 1, True);
    607 	if (position != ctx->text.lastPos)
    608 	    position = SrcScan(ctx->text.source, position - 1,
    609 			       XawstEOL, XawsdLeft, 1, False);
    610 	else
    611 	    break;
    612     }
    613 
    614     if (position != ctx->text.insertPos) {
    615 	XawTextUnsetSelection(w);
    616 	StartAction(ctx, event);
    617 	ctx->text.showposition = True;
    618 	ctx->text.from_left = -1;
    619 	ctx->text.insertPos = position;
    620 	EndAction(ctx);
    621     }
    622     else
    623 	ctx->text.mult = 1;
    624 }
    625 
    626 /*ARGSUSED*/
    627 static void
    628 MoveBackwardParagraph(Widget w, XEvent *event, String *p, Cardinal *n)
    629 {
    630     TextWidget ctx = (TextWidget)w;
    631     XawTextPosition position = ctx->text.insertPos;
    632     short mult = MULT(ctx);
    633 
    634     if (mult < 0) {
    635 	ctx->text.mult = (short)(-mult);
    636 	MoveForwardParagraph(w, event, p, n);
    637 	return;
    638     }
    639 
    640     while (mult--) {
    641 	position = SrcScan(ctx->text.source, position,
    642 			   XawstEOL, XawsdLeft, 1, False) + 1;
    643 
    644 	while (position == SrcScan(ctx->text.source, position,
    645 				   XawstEOL, XawsdLeft, 1, False))
    646 	    if (--position < 0) {
    647 		mult = 0;
    648 		break;
    649 	    }
    650 
    651 	position = SrcScan(ctx->text.source, position,
    652 			   XawstParagraph, XawsdLeft, 1, True);
    653 	if (position > 0 && position < ctx->text.lastPos)
    654 	    ++position;
    655 	else
    656 	    break;
    657     }
    658 
    659     if (position != ctx->text.insertPos) {
    660 	XawTextUnsetSelection(w);
    661 	StartAction(ctx, event);
    662 	ctx->text.showposition = True;
    663 	ctx->text.from_left = -1;
    664 	ctx->text.insertPos = position;
    665 	EndAction(ctx);
    666     }
    667     else
    668 	ctx->text.mult = 1;
    669 }
    670 
    671 /*ARGSUSED*/
    672 static void
    673 MoveToLineEnd(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    674 {
    675     Move((TextWidget)w, event, XawsdRight, XawstEOL, False);
    676 }
    677 
    678 /*ARGSUSED*/
    679 static void
    680 MoveToLineStart(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    681 {
    682     Move((TextWidget)w, event, XawsdLeft, XawstEOL, False);
    683 }
    684 
    685 static void
    686 MoveLine(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
    687 {
    688     XawTextPosition cnew, next_line, ltemp;
    689     int itemp, from_left;
    690     short mult = MULT(ctx);
    691 
    692     StartAction(ctx, event);
    693 
    694     XawTextUnsetSelection((Widget)ctx);
    695 
    696     if (dir == XawsdLeft)
    697 	mult = (short)((mult == 0) ? 5 : mult + 1);
    698 
    699     cnew = SrcScan(ctx->text.source, ctx->text.insertPos,
    700 		   XawstEOL, XawsdLeft, 1, False);
    701 
    702     if (ctx->text.from_left < 0)
    703 	FindDist(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.insertPos,
    704 		 &ctx->text.from_left, &ltemp, &itemp);
    705 
    706     cnew = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL, dir,
    707 		   mult, (dir == XawsdRight));
    708 
    709     next_line = SrcScan(ctx->text.source, cnew, XawstEOL, XawsdRight, 1, False);
    710 
    711     FindPos(ctx->text.sink, cnew, ctx->text.left_margin, ctx->text.from_left,
    712 	    False, &ctx->text.insertPos, &from_left, &itemp);
    713 
    714     if (from_left < ctx->text.from_left) {
    715 	XawTextBlock block;
    716 
    717 	XawTextSourceRead(ctx->text.source, ctx->text.insertPos, &block, 1);
    718 	if (block.length) {
    719 	    if (XawTextFormat(ctx, XawFmtWide)) {
    720 		if (*(wchar_t *)block.ptr == _Xaw_atowc(XawTAB))
    721 		    ++ctx->text.insertPos;
    722 	    }
    723 	    else if (block.ptr[0] == XawTAB)
    724 		++ctx->text.insertPos;
    725 	}
    726     }
    727 
    728     if (ctx->text.insertPos > next_line)
    729 	ctx->text.insertPos = next_line;
    730 
    731     EndAction(ctx);
    732 }
    733 
    734 static void
    735 MoveNextLine(Widget w, XEvent *event, String *p, Cardinal *n)
    736 {
    737     TextWidget ctx = (TextWidget)w;
    738     short mult = MULT(ctx);
    739 
    740     if (mult < 0) {
    741 	ctx->text.mult = (short)(-mult);
    742 	MovePreviousLine(w, event, p, n);
    743 	return;
    744     }
    745 
    746     if (ctx->text.insertPos < ctx->text.lastPos)
    747 	MoveLine(ctx, event, XawsdRight);
    748     else
    749 	ctx->text.mult = 1;
    750 }
    751 
    752 static void
    753 MovePreviousLine(Widget w, XEvent *event, String *p, Cardinal *n)
    754 {
    755     TextWidget ctx = (TextWidget)w;
    756     short mult = MULT(ctx);
    757 
    758     if (mult < 0) {
    759 	ctx->text.mult = (short)(-mult);
    760 	MoveNextLine(w, event, p, n);
    761 	return;
    762     }
    763 
    764     if (ctx->text.lt.top != 0 || (ctx->text.lt.lines > 1 &&
    765 	ctx->text.insertPos >= ctx->text.lt.info[1].position))
    766 	MoveLine(ctx, event, XawsdLeft);
    767     else
    768 	ctx->text.mult = 1;
    769 }
    770 
    771 /*ARGSUSED*/
    772 static void
    773 MoveBeginningOfFile(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    774 {
    775     Move((TextWidget)w, event, XawsdLeft, XawstAll, True);
    776 }
    777 
    778 /*ARGSUSED*/
    779 static void
    780 MoveEndOfFile(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    781 {
    782     Move((TextWidget)w, event, XawsdRight, XawstAll, True);
    783 }
    784 
    785 static void
    786 Scroll(TextWidget ctx, XEvent *event, XawTextScanDirection dir)
    787 {
    788     short mult = MULT(ctx);
    789 
    790     if (mult < 0) {
    791 	mult = (short)(-mult);
    792 	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
    793     }
    794 
    795     if (ctx->text.lt.lines > 1
    796 	&& (dir == XawsdRight
    797 	    || ctx->text.lastPos >= ctx->text.lt.info[1].position)) {
    798 	StartAction(ctx, event);
    799 
    800 	if (dir == XawsdLeft)
    801 	    _XawTextVScroll(ctx, mult);
    802 	else
    803 	    _XawTextVScroll(ctx, -mult);
    804 
    805 	EndAction(ctx);
    806     }
    807     else {
    808 	ctx->text.mult = 1;
    809 #ifndef OLDXAW
    810 	ctx->text.numeric = False;
    811 #endif
    812     }
    813 }
    814 
    815 /*ARGSUSED*/
    816 static void
    817 ScrollOneLineUp(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    818 {
    819     Scroll((TextWidget)w, event, XawsdLeft);
    820 }
    821 
    822 /*ARGSUSED*/
    823 static void
    824 ScrollOneLineDown(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
    825 {
    826     Scroll((TextWidget)w, event, XawsdRight);
    827 }
    828 
    829 static void
    830 MovePage(TextWidget ctx, XEvent *event _X_UNUSED, XawTextScanDirection dir)
    831 {
    832     int scroll_val = 0;
    833     XawTextPosition old_pos;
    834 
    835     ctx->text.from_left = -1;
    836     switch (dir) {
    837 	case XawsdLeft:
    838 	    if (ctx->text.lt.top != 0)
    839 		scroll_val = -Max(1, ctx->text.lt.lines - 1);
    840 	    break;
    841 	case XawsdRight:
    842 	    if (!IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
    843 		scroll_val = Max(1, ctx->text.lt.lines - 1);
    844 	    break;
    845     }
    846 
    847     if (scroll_val)
    848 	XawTextScroll(ctx, scroll_val,
    849 		      ctx->text.left_margin - ctx->text.r_margin.left);
    850 
    851     old_pos = ctx->text.insertPos;
    852     switch (dir) {
    853 	case XawsdRight:
    854 	    if (IsPositionVisible(ctx, Max(0, ctx->text.lastPos)))
    855 		ctx->text.insertPos = Max(0, ctx->text.lastPos);
    856 	    else
    857 		ctx->text.insertPos = ctx->text.lt.top;
    858 	    if (ctx->text.insertPos < old_pos)
    859 		ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
    860 					      XawstEOL, XawsdLeft, 1, False);
    861 	    break;
    862 	case XawsdLeft:
    863 	    if (IsPositionVisible(ctx, 0))
    864 		ctx->text.insertPos = 0;
    865 	    else if (ctx->text.lt.lines)
    866 		ctx->text.insertPos =
    867 		    ctx->text.lt.info[ctx->text.lt.lines - 1].position;
    868 	    else
    869 		ctx->text.insertPos = ctx->text.lt.top;
    870 	    if (ctx->text.insertPos > old_pos)
    871 		ctx->text.insertPos = SrcScan(ctx->text.source, old_pos,
    872 					      XawstEOL, XawsdLeft, 1, False);
    873 	    break;
    874     }
    875 }
    876 
    877 static void
    878 MoveNextPage(Widget w, XEvent *event, String *p, Cardinal *n)
    879 {
    880     TextWidget ctx = (TextWidget)w;
    881     short mult = MULT(ctx);
    882 
    883     if (mult < 0) {
    884 	ctx->text.mult = (short)(-mult);
    885 	MovePreviousPage(w, event, p, n);
    886 	return;
    887     }
    888 
    889     if (ctx->text.insertPos < ctx->text.lastPos) {
    890 	XawTextUnsetSelection(w);
    891 	StartAction(ctx, event);
    892 	ctx->text.clear_to_eol = True;
    893 	while (mult-- && ctx->text.insertPos < ctx->text.lastPos)
    894 	    MovePage(ctx, event, XawsdRight);
    895 	EndAction(ctx);
    896     }
    897     else
    898 	ctx->text.mult = 1;
    899 }
    900 
    901 /*ARGSUSED*/
    902 static void
    903 MovePreviousPage(Widget w, XEvent *event, String *p, Cardinal *n)
    904 {
    905     TextWidget ctx = (TextWidget)w;
    906     short mult = MULT(ctx);
    907 
    908     if (mult < 0) {
    909 	ctx->text.mult = (short)(-mult);
    910 	MoveNextPage(w, event, p, n);
    911 	return;
    912     }
    913 
    914     if (ctx->text.insertPos > 0) {
    915 	XawTextUnsetSelection(w);
    916 	StartAction(ctx, event);
    917 	ctx->text.clear_to_eol = True;
    918 	while (mult-- && ctx->text.insertPos > 0)
    919 	    MovePage(ctx, event, XawsdLeft);
    920 	EndAction(ctx);
    921     }
    922     else
    923 	ctx->text.mult = 1;
    924 }
    925 
    926 /*
    927  * Delete Routines
    928  */
    929 static Bool
    930 MatchSelection(Atom selection, XawTextSelection *s)
    931 {
    932     Atom *match;
    933     int count;
    934 
    935     for (count = 0, match = s->selections; count < s->atom_count;
    936 	 match++, count++)
    937 	if (*match == selection)
    938 	    return (True);
    939 
    940     return (False);
    941 }
    942 
    943 #define SrcCvtSel	XawTextSourceConvertSelection
    944 
    945 static Boolean
    946 ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
    947 		 XtPointer *value, unsigned long *length, int *format)
    948 {
    949     Display *d = XtDisplay(w);
    950     TextWidget ctx = (TextWidget)w;
    951     Widget src = ctx->text.source;
    952     XawTextEditType edit_mode;
    953     XawTextSelectionSalt *salt = NULL;
    954     XawTextSelection *s;
    955 
    956     if (*target == XA_TARGETS(d)) {
    957 	Atom *targetP, *std_targets;
    958 	unsigned long std_length;
    959 
    960 	if (SrcCvtSel(src, selection, target, type, value, length, format))
    961 	    return (True);
    962 	else {
    963 	    Arg args[1];
    964 
    965 	    XtSetArg(args[0], XtNeditType,&edit_mode);
    966 	    XtGetValues(src, args, 1);
    967 	}
    968 
    969 	XmuConvertStandardSelection(w, ctx->text.time, selection,
    970 				    target, type, (XPointer *)&std_targets,
    971 				    &std_length, format);
    972 
    973 	*length = (7 + (unsigned long)(edit_mode == XawtextEdit) + std_length);
    974 	*value = XtMalloc((Cardinal)((unsigned)sizeof(Atom)*(*length)));
    975 	targetP = *(Atom**)value;
    976 	*targetP++ = XA_STRING;
    977 	*targetP++ = XA_TEXT(d);
    978 	*targetP++ = XA_UTF8_STRING(d);
    979 	*targetP++ = XA_COMPOUND_TEXT(d);
    980 	*targetP++ = XA_LENGTH(d);
    981 	*targetP++ = XA_LIST_LENGTH(d);
    982 	*targetP++ = XA_CHARACTER_POSITION(d);
    983 	if (edit_mode == XawtextEdit) {
    984 	    *targetP++ = XA_DELETE(d);
    985 	}
    986 	memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
    987 	XtFree((char*)std_targets);
    988 	*type = XA_ATOM;
    989 	*format = 32;
    990 	return (True);
    991     }
    992 
    993     if (SrcCvtSel(src, selection, target, type, value, length, format))
    994 	return (True);
    995 
    996     for (salt = ctx->text.salt2; salt; salt = salt->next)
    997 	if (MatchSelection (*selection, &salt->s))
    998 	    break;
    999     if (!salt)
   1000 	return (False);
   1001     s = &salt->s;
   1002     if (*target == XA_STRING
   1003 	|| *target == XA_TEXT(d)
   1004 	|| *target == XA_UTF8_STRING(d)
   1005 	|| *target == XA_COMPOUND_TEXT(d)) {
   1006 	if (*target == XA_TEXT(d)) {
   1007 	    if (XawTextFormat(ctx, XawFmtWide))
   1008 		*type = XA_COMPOUND_TEXT(d);
   1009 	    else
   1010 		*type = XA_STRING;
   1011 	}
   1012 	else
   1013 	  *type = *target;
   1014 
   1015 	/*
   1016 	 * If salt is True, the salt->contents stores CT string,
   1017 	 * its length is measured in bytes.
   1018 	 * Refer to _XawTextSaltAwaySelection()
   1019 	 *
   1020 	 * by Li Yuhong, Mar. 20, 1991.
   1021 	 */
   1022 	if (!salt) {
   1023 	    *value = (char *)_XawTextGetSTRING(ctx, s->left, s->right);
   1024 	    if (XawTextFormat(ctx, XawFmtWide)) {
   1025 		XTextProperty textprop;
   1026 		if (XwcTextListToTextProperty(d, (wchar_t**)value, 1,
   1027 					      XCompoundTextStyle, &textprop)
   1028 		    < Success) {
   1029 		    XtFree(*value);
   1030 		    return (False);
   1031 		}
   1032 		XtFree(*value);
   1033 		*value = (XtPointer)textprop.value;
   1034 		*length = textprop.nitems;
   1035 	    }
   1036 	    else
   1037 		*length = strlen(*value);
   1038 	}
   1039 	else {
   1040 	    *value = XtMalloc((Cardinal)((size_t)(salt->length + 1) * sizeof(unsigned char)));
   1041 	    strcpy (*value, salt->contents);
   1042 	    *length = (unsigned long)salt->length;
   1043 	}
   1044 	/* Got *value,*length, now in COMPOUND_TEXT format. */
   1045 	if (XawTextFormat(ctx, XawFmtWide)) {
   1046 	    if (*type == XA_STRING) {
   1047 		wchar_t **wlist;
   1048 		int count;
   1049 		XTextProperty textprop = {
   1050 		    .encoding = XA_COMPOUND_TEXT(d),
   1051 		    .value = (unsigned char *)*value,
   1052 		    .nitems = strlen(*value),
   1053 		    .format = 8
   1054 		};
   1055 
   1056 		if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
   1057 		     < Success
   1058 		    || count < 1) {
   1059 		    XtFree(*value);
   1060 		    return (False);
   1061 		}
   1062 		XtFree(*value);
   1063 		if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
   1064 		     < Success) {
   1065 		    XwcFreeStringList((wchar_t**)wlist);
   1066 		    return (False);
   1067 		}
   1068 		*value = (XtPointer)textprop.value;
   1069 		*length = textprop.nitems;
   1070 		XwcFreeStringList((wchar_t**) wlist);
   1071 	    }
   1072 	    else if (*type == XA_UTF8_STRING(d)) {
   1073 		char **list;
   1074 		int count;
   1075 		XTextProperty textprop = {
   1076 		    .encoding = XA_COMPOUND_TEXT(d),
   1077 		    .value = (unsigned char *)*value,
   1078 		    .nitems = strlen(*value),
   1079 		    .format = 8
   1080 		};
   1081 
   1082 		if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
   1083 		    < Success
   1084 		    || count < 1) {
   1085 		    XtFree(*value);
   1086 		    return (False);
   1087 		}
   1088 		XtFree(*value);
   1089 		*value = *list;
   1090 		*length = strlen(*list);
   1091 		XFree(list);
   1092 	    }
   1093 	}
   1094 	*format = 8;
   1095 	return (True);
   1096     }
   1097 
   1098     if (*target == XA_LIST_LENGTH(d) || *target == XA_LENGTH(d)) {
   1099 	long *temp;
   1100 
   1101 	temp = (long *)XtMalloc(sizeof(long));
   1102 	if (*target == XA_LIST_LENGTH(d))
   1103 	    *temp = 1L;
   1104 	else			/* *target == XA_LENGTH(d) */
   1105 	    *temp = (long)(s->right - s->left);
   1106 
   1107 	*value = (XPointer)temp;
   1108 	*type = XA_INTEGER;
   1109 	*length = 1L;
   1110 	*format = 32;
   1111 	return (True);
   1112     }
   1113 
   1114     if (*target == XA_CHARACTER_POSITION(d)) {
   1115 	long *temp;
   1116 
   1117 	temp = (long *) XtMalloc(2 * sizeof(long));
   1118 	temp[0] = (long)(s->left + 1);
   1119 	temp[1] = s->right;
   1120 	*value = (XPointer)temp;
   1121 	*type = XA_SPAN(d);
   1122 	*length = 2L;
   1123 	*format = 32;
   1124 	return (True);
   1125     }
   1126 
   1127     if (*target == XA_DELETE(d)) {
   1128 	if (!salt)
   1129 	    _XawTextZapSelection(ctx, NULL, True);
   1130 	*value = NULL;
   1131 	*type = XA_NULL(d);
   1132 	*length = 0;
   1133 	*format = 32;
   1134 	return (True);
   1135     }
   1136 
   1137     if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
   1138 				    (XPointer *)value, length, format))
   1139 	return (True);
   1140 
   1141     return (False);
   1142 }
   1143 
   1144 static void
   1145 LoseSelection(Widget w, Atom *selection)
   1146 {
   1147     _LoseSelection(w, selection, NULL, NULL);
   1148 }
   1149 
   1150 static void
   1151 _LoseSelection(Widget w, Atom *selection, char **contents _X_UNUSED, int *length _X_UNUSED)
   1152 {
   1153     TextWidget ctx = (TextWidget)w;
   1154     Atom *atomP;
   1155     int i;
   1156     XawTextSelectionSalt *salt, *prevSalt, *nextSalt;
   1157 
   1158     prevSalt = 0;
   1159     for (salt = ctx->text.salt2; salt; salt = nextSalt) {
   1160 	atomP = salt->s.selections;
   1161 	nextSalt = salt->next;
   1162 	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
   1163 	    if (*selection == *atomP)
   1164 		*atomP = (Atom)0;
   1165 
   1166 	while (salt->s.atom_count
   1167 	       && salt->s.selections[salt->s.atom_count-1] == 0)
   1168 	    salt->s.atom_count--;
   1169 
   1170 	/*
   1171 	 * Must walk the selection list in opposite order from UnsetSelection.
   1172 	 */
   1173 	atomP = salt->s.selections;
   1174 	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
   1175 	    if (*atomP == (Atom)0) {
   1176 		*atomP = salt->s.selections[--salt->s.atom_count];
   1177 
   1178 		while (salt->s.atom_count
   1179 		       && salt->s.selections[salt->s.atom_count-1] == 0)
   1180 		    salt->s.atom_count--;
   1181 	    }
   1182 	if (salt->s.atom_count == 0) {
   1183 #ifndef OLDXAW
   1184 	    if (contents == NULL) {
   1185 		XawTextKillRing *kill_ring = XtNew(XawTextKillRing);
   1186 
   1187 		kill_ring->next = xaw_text_kill_ring;
   1188 		kill_ring->contents = salt->contents;
   1189 		kill_ring->length = salt->length;
   1190 		kill_ring->format = XawFmt8Bit;
   1191 		xaw_text_kill_ring = kill_ring;
   1192 		kill_ring_prev.next = xaw_text_kill_ring;
   1193 
   1194 		if (++num_kill_rings > MAX_KILL_RINGS) {
   1195 		    XawTextKillRing *tail = NULL;
   1196 
   1197 		    while (kill_ring->next) {
   1198 			tail = kill_ring;
   1199 			kill_ring = kill_ring->next;
   1200 		    }
   1201 		    if (tail != NULL && kill_ring->refcount == 0) {
   1202 			--num_kill_rings;
   1203 			tail->next = NULL;
   1204 			XtFree(kill_ring->contents);
   1205 			XtFree((char*)kill_ring);
   1206 		    }
   1207 		}
   1208 	    }
   1209 	    else {
   1210 		*contents = salt->contents;
   1211 		*length = salt->length;
   1212 	    }
   1213 #endif
   1214 	    if (prevSalt)
   1215 		prevSalt->next = nextSalt;
   1216 	    else
   1217 		ctx->text.salt2 = nextSalt;
   1218 
   1219 	    XtFree((char *)salt->s.selections);
   1220 	    XtFree((char *)salt);
   1221 	}
   1222 	else
   1223 	    prevSalt = salt;
   1224     }
   1225 }
   1226 
   1227 static void
   1228 _DeleteOrKill(TextWidget ctx, XawTextPosition from, XawTextPosition to,
   1229 	      Bool kill)
   1230 {
   1231     XawTextBlock text;
   1232 
   1233 #ifndef OLDXAW
   1234     if (ctx->text.kill_ring_ptr) {
   1235 	--ctx->text.kill_ring_ptr->refcount;
   1236 	ctx->text.kill_ring_ptr = NULL;
   1237     }
   1238 #endif
   1239     if (kill && from < to) {
   1240 #ifndef OLDXAW
   1241 	Bool append = False;
   1242 	char *ring = NULL;
   1243 	XawTextPosition old_from = from;
   1244 #endif
   1245 	char *string;
   1246 	int size = 0, length;
   1247 	XawTextSelectionSalt *salt;
   1248 	Atom selection = XInternAtom(XtDisplay(ctx), "SECONDARY", False);
   1249 
   1250 #ifndef OLDXAW
   1251 	if (ctx->text.kill_ring == KILL_RING_APPEND) {
   1252 	    old_from = ctx->text.salt2->s.left;
   1253 	    append = True;
   1254 	}
   1255 	else
   1256 	    ctx->text.kill_ring = KILL_RING_BEGIN;
   1257 
   1258 	if (append)
   1259 	    _LoseSelection((Widget)ctx, &selection, &ring, &size);
   1260 	else
   1261 #endif
   1262 	    LoseSelection((Widget)ctx, &selection);
   1263 
   1264 	salt = (XawTextSelectionSalt*)XtMalloc(sizeof(XawTextSelectionSalt));
   1265 	salt->s.selections = (Atom *)XtMalloc(sizeof(Atom));
   1266 	salt->s.left = from;
   1267 	salt->s.right = to;
   1268 
   1269 	string = (char *)_XawTextGetSTRING(ctx, from, to);
   1270 
   1271 	if (XawTextFormat(ctx, XawFmtWide)) {
   1272 	    XTextProperty textprop;
   1273 
   1274 	    if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
   1275 					  (wchar_t**)(&string),
   1276 					  1, XCompoundTextStyle,
   1277 					  &textprop) <  Success) {
   1278 		XtFree(string);
   1279 		XtFree((char*)salt->s.selections);
   1280 		XtFree((char*)salt);
   1281 		return;
   1282 	    }
   1283 	    XtFree(string);
   1284 	    string = (char *)textprop.value;
   1285 	    length = (int)textprop.nitems;
   1286 	}
   1287 	else
   1288 	    length = (int)strlen(string);
   1289 
   1290 	salt->length = length + size;
   1291 
   1292 #ifndef OLDXAW
   1293 	if (!append)
   1294 	    salt->contents = string;
   1295 	else {
   1296 	    salt->contents = XtMalloc((Cardinal)(length + size + 1));
   1297 	    if (from >= old_from) {
   1298 		if (ring != NULL) {
   1299 		    strncpy(salt->contents, ring, (size_t)size);
   1300 		    salt->contents[size] = '\0';
   1301 		} else {
   1302 		    salt->contents[size = 0] = '\0';
   1303 		}
   1304 		strncat(salt->contents, string, (size_t)length);
   1305 	    }
   1306 	    else {
   1307 		strncpy(salt->contents, string, (size_t)length);
   1308 		salt->contents[length] = '\0';
   1309 		if (ring != NULL) {
   1310 		    strncat(salt->contents, ring, (size_t)size);
   1311 		} else {
   1312 		    size = 0;
   1313 		}
   1314 	    }
   1315 	    salt->contents[length + size] = '\0';
   1316 	    XtFree(ring);
   1317 	    XtFree(string);
   1318 	}
   1319 
   1320 	kill_ring_prev.contents = salt->contents;
   1321 	kill_ring_prev.length = salt->length;
   1322 	kill_ring_prev.format = XawFmt8Bit;
   1323 #else
   1324 	salt->contents = string;
   1325 #endif
   1326 
   1327 	salt->next = ctx->text.salt2;
   1328 	ctx->text.salt2 = salt;
   1329 
   1330 #ifndef OLDXAW
   1331 	if (append)
   1332 	    ctx->text.kill_ring = KILL_RING_BEGIN;
   1333 #endif
   1334 
   1335 	salt->s.selections[0] = selection;
   1336 
   1337 	XtOwnSelection((Widget)ctx, selection, ctx->text.time,
   1338 		       ConvertSelection, LoseSelection, NULL);
   1339 	salt->s.atom_count = 1;
   1340     }
   1341     text.length = 0;
   1342     text.firstPos = 0;
   1343 
   1344     text.format = (unsigned long)_XawTextFormat(ctx);
   1345     text.ptr = (char*)"";
   1346 
   1347     if (_XawTextReplace(ctx, from, to, &text)) {
   1348 	XBell(XtDisplay(ctx), 50);
   1349 	return;
   1350     }
   1351     ctx->text.from_left = -1;
   1352     ctx->text.insertPos = from;
   1353     ctx->text.showposition = TRUE;
   1354 }
   1355 
   1356 static void
   1357 DeleteOrKill(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
   1358 	     XawTextScanType type, Bool include, Bool kill)
   1359 {
   1360     XawTextPosition from, to;
   1361     short mult = MULT(ctx);
   1362 
   1363     if (mult < 0) {
   1364 	mult = (short)(-mult);
   1365 	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
   1366     }
   1367 
   1368     StartAction(ctx, event);
   1369 #ifndef OLDXAW
   1370     if (mult == 1)
   1371 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
   1372 #endif
   1373     to = SrcScan(ctx->text.source, ctx->text.insertPos,
   1374 		 type, dir, mult, (Boolean)include);
   1375 
   1376     /*
   1377      * If no movement actually happened, then bump the count and try again.
   1378      * This causes the character position at the very beginning and end of
   1379      * a boundary to act correctly
   1380      */
   1381     if (to == ctx->text.insertPos)
   1382 	to = SrcScan(ctx->text.source, ctx->text.insertPos,
   1383 		     type, dir, mult + 1, (Boolean)include);
   1384 
   1385     if (dir == XawsdLeft) {
   1386 	from = to;
   1387 	to = ctx->text.insertPos;
   1388     }
   1389     else
   1390 	from = ctx->text.insertPos;
   1391 
   1392     _DeleteOrKill(ctx, from, to, kill);
   1393     EndAction(ctx);
   1394 }
   1395 
   1396 static void
   1397 Delete(Widget w, XEvent *event, String *p, Cardinal *n)
   1398 {
   1399     TextWidget ctx = (TextWidget)w;
   1400 
   1401     if (ctx->text.s.left != ctx->text.s.right)
   1402 	DeleteCurrentSelection(w, event, p, n);
   1403     else
   1404 	DeleteBackwardChar(w, event, p, n);
   1405 }
   1406 
   1407 static void
   1408 DeleteChar(Widget w, XEvent *event, XawTextScanDirection dir)
   1409 {
   1410     TextWidget ctx = (TextWidget)w;
   1411     short mul = MULT(ctx);
   1412 
   1413     if (mul < 0) {
   1414 	mul = -mul;
   1415 	ctx->text.mult = mul;
   1416 	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
   1417     }
   1418     DeleteOrKill(ctx, event, dir, XawstPositions, True, False);
   1419 #ifndef OLDXAW
   1420     if (mul == 1)
   1421 	_XawSourceSetUndoErase((TextSrcObject)ctx->text.source,
   1422 			       dir == XawsdLeft ? -1 : 1);
   1423 #endif
   1424 }
   1425 
   1426 /*ARGSUSED*/
   1427 static void
   1428 DeleteForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   1429 {
   1430     DeleteChar(w, event, XawsdRight);
   1431 }
   1432 
   1433 /*ARGSUSED*/
   1434 static void
   1435 DeleteBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   1436 {
   1437     DeleteChar(w, event, XawsdLeft);
   1438 }
   1439 
   1440 static void
   1441 DeleteForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
   1442 {
   1443     XawTextScanType type;
   1444 
   1445     if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
   1446 	type = XawstAlphaNumeric;
   1447     else
   1448 	type = XawstWhiteSpace;
   1449 
   1450     DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, False);
   1451 }
   1452 
   1453 static void
   1454 DeleteBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
   1455 {
   1456     XawTextScanType type;
   1457 
   1458     if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
   1459 	type = XawstAlphaNumeric;
   1460     else
   1461 	type = XawstWhiteSpace;
   1462 
   1463     DeleteOrKill((TextWidget)w, event, XawsdLeft, type, False, False);
   1464 }
   1465 
   1466 static void
   1467 KillForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
   1468 {
   1469     XawTextScanType type;
   1470 
   1471     if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
   1472 	type = XawstAlphaNumeric;
   1473     else
   1474 	type = XawstWhiteSpace;
   1475 
   1476     DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, True);
   1477 }
   1478 
   1479 static void
   1480 KillBackwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
   1481 {
   1482     XawTextScanType type;
   1483 
   1484     if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
   1485 	type = XawstAlphaNumeric;
   1486     else
   1487 	type = XawstWhiteSpace;
   1488 
   1489     DeleteOrKill((TextWidget) w, event, XawsdLeft, type, False, True);
   1490 }
   1491 
   1492 /*ARGSUSED*/
   1493 static void
   1494 KillToEndOfLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   1495 {
   1496     TextWidget ctx = (TextWidget)w;
   1497     XawTextPosition end_of_line;
   1498     XawTextScanDirection dir = XawsdRight;
   1499     short mult = MULT(ctx);
   1500 
   1501     if (mult < 0) {
   1502 	dir = XawsdLeft;
   1503 	mult = (short)(-mult);
   1504     }
   1505 
   1506     StartAction(ctx, event);
   1507     end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
   1508 			  dir, mult, False);
   1509     if (end_of_line == ctx->text.insertPos)
   1510 	end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
   1511 			      dir, mult, True);
   1512 
   1513     if (dir == XawsdRight)
   1514 	_DeleteOrKill(ctx, ctx->text.insertPos, end_of_line, True);
   1515     else
   1516 	_DeleteOrKill(ctx, end_of_line, ctx->text.insertPos, True);
   1517     EndAction(ctx);
   1518 }
   1519 
   1520 /*ARGSUSED*/
   1521 static void
   1522 KillToEndOfParagraph(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   1523 {
   1524     DeleteOrKill((TextWidget)w, event, XawsdRight, XawstParagraph, False, True);
   1525 }
   1526 
   1527 void
   1528 _XawTextZapSelection(TextWidget ctx, XEvent *event, Bool kill)
   1529 {
   1530     StartAction(ctx, event);
   1531     _DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, kill);
   1532     EndAction(ctx);
   1533 }
   1534 
   1535 /*ARGSUSED*/
   1536 static void
   1537 KillCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   1538 {
   1539     _XawTextZapSelection((TextWidget) w, event, True);
   1540 }
   1541 
   1542 #ifndef OLDXAW
   1543 /*ARGSUSED*/
   1544 static void
   1545 KillRingYank(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   1546 {
   1547     TextWidget ctx = (TextWidget)w;
   1548     XawTextPosition insertPos = ctx->text.insertPos;
   1549     Bool first_yank = False;
   1550 
   1551     if (ctx->text.s.left != ctx->text.s.right)
   1552 	XawTextUnsetSelection((Widget)ctx);
   1553 
   1554     StartAction(ctx, event);
   1555 
   1556     if (ctx->text.kill_ring_ptr == NULL) {
   1557 	ctx->text.kill_ring_ptr = &kill_ring_prev;
   1558 	++ctx->text.kill_ring_ptr->refcount;
   1559 	ctx->text.s.left = ctx->text.s.right = insertPos;
   1560 	first_yank = True;
   1561     }
   1562     if (ctx->text.kill_ring_ptr) {
   1563 	int mul = MULT(ctx);
   1564 	XawTextBlock text;
   1565 
   1566 	if (!first_yank) {
   1567 	    if (mul < 0)
   1568 		mul = 1;
   1569 	    --ctx->text.kill_ring_ptr->refcount;
   1570 	    while (mul--) {
   1571 		if ((ctx->text.kill_ring_ptr = ctx->text.kill_ring_ptr->next) == NULL)
   1572 		    ctx->text.kill_ring_ptr = &kill_ring_null;
   1573 	    }
   1574 	    ++ctx->text.kill_ring_ptr->refcount;
   1575 	}
   1576 	text.firstPos = 0;
   1577 	text.length = ctx->text.kill_ring_ptr->length;
   1578 	text.ptr = ctx->text.kill_ring_ptr->contents;
   1579 	text.format = ctx->text.kill_ring_ptr->format;
   1580 
   1581 	if (_XawTextReplace(ctx, ctx->text.s.left, insertPos, &text) == XawEditDone) {
   1582 	    ctx->text.kill_ring = KILL_RING_YANK;
   1583 	    ctx->text.insertPos = ctx->text.s.left + text.length;
   1584 	}
   1585     }
   1586     else
   1587 	XBell(XtDisplay(w), 0);
   1588 
   1589     EndAction(ctx);
   1590 }
   1591 #endif /* OLDXAW */
   1592 
   1593 /*ARGSUSED*/
   1594 static void
   1595 DeleteCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   1596 {
   1597     _XawTextZapSelection((TextWidget)w, event, False);
   1598 }
   1599 
   1600 #ifndef OLDXAW
   1601 #define CHECK_SAVE()						\
   1602 	if (save && !save->ptr)					\
   1603 	    save->ptr = _XawTextGetText(ctx, save->firstPos,	\
   1604 		save->firstPos + save->length)
   1605 static Bool
   1606 StripSpaces(TextWidget ctx, XawTextPosition left, XawTextPosition right,
   1607 	    XawTextPosition *pos, int num_pos, XawTextBlock *save)
   1608 {
   1609     Bool done, space;
   1610     int i, cpos, count = 0;
   1611     XawTextBlock block, text;
   1612     XawTextPosition ipos, position = left, tmp = left;
   1613 
   1614     text.firstPos = 0;
   1615     text.format = XawFmt8Bit;
   1616     text.ptr = (char*)" ";
   1617     text.length = 1;
   1618 
   1619     XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left));
   1620     done = False;
   1621     space = False;
   1622     /* convert tabs and returns to spaces */
   1623     while (!done) {
   1624 	if (XawTextFormat(ctx, XawFmt8Bit)) {
   1625 	    for (i = 0; i < block.length; i++)
   1626 		if (block.ptr[i] == '\t' || block.ptr[i] == '\n') {
   1627 		    space = True;
   1628 		    break;
   1629 		}
   1630 	}
   1631 	else {
   1632 	    wchar_t *wptr = (wchar_t*)block.ptr;
   1633 	    for (i = 0; i < block.length; i++)
   1634 		if (wptr[i] == _Xaw_atowc('\t') || wptr[i] == _Xaw_atowc('\n')) {
   1635 		    space = True;
   1636 		    break;
   1637 		}
   1638 	}
   1639 	if (space) {
   1640 	    CHECK_SAVE();
   1641 	    if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text))
   1642 		return (False);
   1643 	    space = False;
   1644 	}
   1645 	tmp += i;
   1646 	position = XawTextSourceRead(ctx->text.source, tmp,
   1647 				     &block, (int)(right - tmp));
   1648 	if (block.length == 0 || tmp == position || tmp >= right)
   1649 	    done = True;
   1650     }
   1651 
   1652     text.ptr = (char*)"";
   1653     text.length = 0;
   1654     position = tmp = left;
   1655     XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left));
   1656     ipos = ctx->text.insertPos;
   1657     done = False;
   1658     while (!done) {
   1659 	if (XawTextFormat(ctx, XawFmt8Bit)) {
   1660 	    for (i = 0; i < block.length; i++)
   1661 		if (block.ptr[i] == ' ')
   1662 		    ++count;
   1663 		else if (count == 1)
   1664 		    count = 0;
   1665 		else if (count)
   1666 		    break;
   1667 	}
   1668 	else {
   1669 	    wchar_t *wptr = (wchar_t*)block.ptr;
   1670 	    for (i = 0; i < block.length; i++)
   1671 		if (wptr[i] == _Xaw_atowc(' '))
   1672 		    ++count;
   1673 		else if (count == 1)
   1674 		    count = 0;
   1675 		else if (count)
   1676 		    break;
   1677 	}
   1678 	if (--count > 0) {
   1679 	    CHECK_SAVE();
   1680 	    if (_XawTextReplace(ctx, tmp + i - count, tmp + i, &text))
   1681 		return (False);
   1682 	    right -= count;
   1683 	    if (num_pos) {
   1684 		for (cpos = 0; cpos < num_pos; cpos++) {
   1685 		    if (tmp + i - count < pos[cpos]) {
   1686 			if (tmp + i < pos[cpos])
   1687 			    pos[cpos] -= count;
   1688 			else
   1689 			    pos[cpos] = tmp + i - count;
   1690 		    }
   1691 		}
   1692 	    }
   1693 	    else {
   1694 		if (tmp + i - count < ipos) {
   1695 		    if (tmp + i < ipos)
   1696 			ipos -= count;
   1697 		    else
   1698 			ipos = tmp + i - count;
   1699 		}
   1700 	    }
   1701 	    tmp += i - count;
   1702 	}
   1703 	else
   1704 	    tmp += i + 1;
   1705 	count = 0;
   1706 	position = XawTextSourceRead(ctx->text.source, tmp,
   1707 				     &block, (int)(right - tmp));
   1708 	if (block.length == 0 || tmp == position || tmp >= right)
   1709 	    done = True;
   1710     }
   1711     if (!num_pos)
   1712 	ctx->text.insertPos = ipos;
   1713 
   1714     return (True);
   1715 }
   1716 
   1717 static Bool
   1718 Tabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
   1719        XawTextPosition *pos, int num_pos, XawTextBlock *save)
   1720 {
   1721     Bool done, zero;
   1722     int i, cpos, count = 0, column = 0, offset = 0;
   1723     XawTextBlock text, block;
   1724     XawTextPosition ipos, position = left, tmp = left;
   1725     TextSinkObject sink = (TextSinkObject)ctx->text.sink;
   1726     short *char_tabs = sink->text_sink.char_tabs;
   1727     int tab_count = sink->text_sink.tab_count;
   1728     int tab_index = 0, tab_column = 0, TAB_SIZE = DEFAULT_TAB_SIZE;
   1729 
   1730     text.firstPos = 0;
   1731     text.ptr = (char*)"\t";
   1732     text.format = XawFmt8Bit;
   1733     text.length = 1;
   1734 
   1735     XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left));
   1736     ipos = ctx->text.insertPos;
   1737     done = zero = False;
   1738     if (tab_count)
   1739 	TAB_SIZE = *char_tabs;
   1740     while (!done) {
   1741 	if (XawTextFormat(ctx, XawFmt8Bit)) {
   1742 	    for (i = 0; i < block.length; i++) {
   1743 		++offset;
   1744 		++column;
   1745 		if (tab_count) {
   1746 		    if (column > tab_column + char_tabs[tab_index]) {
   1747 			TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
   1748 			if (++tab_index >= tab_count) {
   1749 			    tab_column += char_tabs[tab_count - 1];
   1750 			    tab_index = 0;
   1751 			}
   1752 		    }
   1753 		}
   1754 		if (block.ptr[i] == ' ') {
   1755 		    if (++count > TAB_SIZE)
   1756 			count %= TAB_SIZE;
   1757 		    if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
   1758 			(!tab_count && column % TAB_SIZE == 0)) {
   1759 			if (count % (TAB_SIZE + 1) > 1)
   1760 			    break;
   1761 			else
   1762 			    count = 0;
   1763 		    }
   1764 		}
   1765 		else {
   1766 		    if (block.ptr[i] == '\n') {
   1767 			zero = True;
   1768 			break;
   1769 		    }
   1770 		    count = 0;
   1771 		}
   1772 	    }
   1773 	}
   1774 	else {
   1775 	    wchar_t *wptr = (wchar_t*)block.ptr;
   1776 	    for (i = 0; i < block.length; i++) {
   1777 		++offset;
   1778 		++column;
   1779 		if (tab_count) {
   1780 		    if (column > tab_column + char_tabs[tab_index]) {
   1781 			TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
   1782 			if (++tab_index >= tab_count) {
   1783 			    tab_column += char_tabs[tab_count - 1];
   1784 			    tab_index = 0;
   1785 			}
   1786 		    }
   1787 		}
   1788 		if (wptr[i] == _Xaw_atowc(' ')) {
   1789 		    if (++count > TAB_SIZE)
   1790 			count %= TAB_SIZE;
   1791 		    if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
   1792 			(!tab_count && column % TAB_SIZE == 0)) {
   1793 			if (count % (TAB_SIZE + 1) > 1)
   1794 			    break;
   1795 			else
   1796 			    count = 0;
   1797 		    }
   1798 		}
   1799 		else {
   1800 		    if (wptr[i] == _Xaw_atowc('\n')) {
   1801 			zero = True;
   1802 			break;
   1803 		    }
   1804 		    count = 0;
   1805 		}
   1806 	    }
   1807 	}
   1808 	count %= TAB_SIZE + 1;
   1809 	if (!zero && count > 1 && i < block.length) {
   1810 	    CHECK_SAVE();
   1811 	    if (_XawTextReplace(ctx, tmp + i - count + 1, tmp + i + 1, &text))
   1812 		return (False);
   1813 	    right -= count - 1;
   1814 	    offset -= count - 1;
   1815 	    if (num_pos) {
   1816 		for (cpos = 0; cpos < num_pos; cpos++) {
   1817 		    if (tmp + i - count + 1 < pos[cpos]) {
   1818 			if (tmp + i + 1 < pos[cpos])
   1819 			    pos[cpos] -= count;
   1820 			else
   1821 			    pos[cpos] = tmp + i - count + 1;
   1822 			++pos[cpos];
   1823 		    }
   1824 		}
   1825 	    }
   1826 	    else {
   1827 		if (tmp + i - count + 1 < ipos) {
   1828 		    if (tmp + i + 1 < ipos)
   1829 			ipos -= count;
   1830 		    else
   1831 			ipos = tmp + i - count + 1;
   1832 		    ++ipos;
   1833 		}
   1834 	    }
   1835 	}
   1836 	if (count)
   1837 	    --count;
   1838 	if (zero) {
   1839 	    count = column = 0;
   1840 	    zero = False;
   1841 	    if (tab_count) {
   1842 		tab_column = tab_index = 0;
   1843 		TAB_SIZE = *char_tabs;
   1844 	    }
   1845 	}
   1846 	else if (i < block.length)
   1847 	    count = 0;
   1848 	tmp = left + offset;
   1849 	position = XawTextSourceRead(ctx->text.source, tmp,
   1850 				     &block, (int)(right - tmp));
   1851 	if (tmp == position || tmp >= right)
   1852 	    done = True;
   1853     }
   1854     if (!num_pos)
   1855 	ctx->text.insertPos = ipos;
   1856 
   1857     return (True);
   1858 }
   1859 
   1860 static Bool
   1861 Untabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
   1862 	 XawTextPosition *pos, int num_pos, XawTextBlock *save)
   1863 {
   1864     Bool done, zero;
   1865     int i, cpos, count = 0, diff = 0;
   1866     XawTextBlock block, text;
   1867     XawTextPosition ipos, position = left, tmp = left;
   1868     TextSinkObject sink = (TextSinkObject)ctx->text.sink;
   1869     short *char_tabs = sink->text_sink.char_tabs;
   1870     int tab_count = sink->text_sink.tab_count;
   1871     int tab_index = 0, tab_column = 0, tab_base = 0;
   1872     static char *tabs = (char*)"        ";
   1873 
   1874     text.firstPos = 0;
   1875     text.format = XawFmt8Bit;
   1876     text.ptr = tabs;
   1877 
   1878     XawTextSourceRead(ctx->text.source, position, &block, (int)(right - left));
   1879     ipos = ctx->text.insertPos;
   1880     done = False;
   1881     zero = False;
   1882     while (!done) {
   1883 	if (XawTextFormat(ctx, XawFmt8Bit))
   1884 	    for (i = 0; i < block.length; i++) {
   1885 		if (block.ptr[i] != '\t') {
   1886 		    ++count;
   1887 		    if (block.ptr[i] == '\n') {
   1888 			zero = True;
   1889 			break;
   1890 		    }
   1891 		}
   1892 		else
   1893 		    break;
   1894 	}
   1895 	else {
   1896 	    wchar_t *wptr = (wchar_t*)block.ptr;
   1897 	    for (i = 0; i < block.length; i++)
   1898 		if (wptr[i] != _Xaw_atowc('\t')) {
   1899 		    ++count;
   1900 		    if (wptr[i] != _Xaw_atowc('\n')) {
   1901 			zero = True;
   1902 			break;
   1903 		    }
   1904 		}
   1905 		else
   1906 		    break;
   1907 	}
   1908 	if (!zero && i < block.length) {
   1909 	    if (tab_count) {
   1910 		while (tab_base + tab_column <= count) {
   1911 		    for (; tab_index < tab_count; ++tab_index)
   1912 			if (tab_base + char_tabs[tab_index] > count) {
   1913 			    tab_column = char_tabs[tab_index];
   1914 			    break;
   1915 			}
   1916 		    if (tab_index >= tab_count) {
   1917 			tab_base += char_tabs[tab_count - 1];
   1918 			tab_column = tab_index = 0;
   1919 		    }
   1920 		}
   1921 		text.length = (tab_base + tab_column) - count;
   1922 		if (text.length > 8) {
   1923 		    int j;
   1924 
   1925 		    text.ptr = XtMalloc((Cardinal)text.length);
   1926 		    for (j = 0; j < text.length; j++)
   1927 			text.ptr[j] = ' ';
   1928 		}
   1929 		else
   1930 		    text.ptr = tabs;
   1931 	    }
   1932 	    else
   1933 		text.length = DEFAULT_TAB_SIZE - (count % DEFAULT_TAB_SIZE);
   1934 	    CHECK_SAVE();
   1935 	    if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text)) {
   1936 		if (tab_count && text.length > 8)
   1937 		    XtFree(text.ptr);
   1938 		return (False);
   1939 	    }
   1940 	    if (tab_count && text.length > 8)
   1941 		XtFree(text.ptr);
   1942 	    count += text.length;
   1943 	    right += text.length - 1;
   1944 	    if (num_pos) {
   1945 		for (cpos = 0; cpos < num_pos; cpos++) {
   1946 		    if (tmp + i < pos[cpos]) {
   1947 			if (tmp + i + 1 < pos[cpos])
   1948 			    --pos[cpos];
   1949 			else
   1950 			    pos[cpos] = tmp + i;
   1951 			pos[cpos] += text.length;
   1952 		    }
   1953 		}
   1954 	    }
   1955 	    else {
   1956 		if (tmp + i < ipos) {
   1957 		    if (tmp + i + 1 < ipos)
   1958 			--ipos;
   1959 		    else
   1960 			ipos = tmp + i;
   1961 		    ipos += text.length;
   1962 		}
   1963 	    }
   1964 	}
   1965 	tmp = left + count + diff;
   1966 	if (zero) {
   1967 	    diff += count;
   1968 	    count = 0;
   1969 	    zero = False;
   1970 	    if (tab_count)
   1971 		tab_base = tab_column = tab_index = 0;
   1972 	}
   1973 	position = XawTextSourceRead(ctx->text.source, tmp,
   1974 				     &block, (int)(right - tmp));
   1975 	if (tmp == position || tmp >= right)
   1976 	    done = True;
   1977     }
   1978     if (!num_pos)
   1979 	ctx->text.insertPos = ipos;
   1980 
   1981     return (True);
   1982 }
   1983 
   1984 static int
   1985 FormatText(TextWidget ctx, XawTextPosition left, Bool force,
   1986 	   XawTextPosition *pos, int num_pos)
   1987 {
   1988     char *ptr = NULL;
   1989     Bool freepos = False, undo, paragraph = pos != NULL;
   1990     int i, result;
   1991     XawTextBlock block, *text;
   1992     XawTextPosition end = ctx->text.lastPos, buf[32];
   1993     TextSrcObject src = (TextSrcObject)ctx->text.source;
   1994     XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
   1995 				    XawsdRight, 1, False);
   1996 
   1997     undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
   1998     if (undo) {
   1999 	if (!pos) {
   2000 	    num_pos = (int)src->textSrc.num_text;
   2001 	    pos = (XawStackAlloc(sizeof(XawTextPosition) * (size_t)num_pos, buf));
   2002 	    for (i = 0; i < num_pos; i++)
   2003 		pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
   2004 	    freepos = True;
   2005 	}
   2006 	else
   2007 	    freepos = False;
   2008 	src->textSrc.undo_state = True;
   2009 	block.ptr = NULL;
   2010 	block.firstPos = (int)left;
   2011 	block.length = (int)(right - left);
   2012 	text = &block;
   2013     }
   2014     else
   2015 	text = NULL;
   2016 
   2017     result = DoFormatText(ctx, left, force, 1, text, pos, num_pos, paragraph);
   2018     if (undo && result == XawEditDone && block.ptr) {
   2019 	char *lbuf, *rbuf;
   2020 	unsigned llen, rlen, size;
   2021 
   2022 	ptr = lbuf = block.ptr;
   2023 	llen = (unsigned)block.length;
   2024 	rlen = (unsigned)(llen + (ctx->text.lastPos - end));
   2025 
   2026 	block.firstPos = 0;
   2027 	block.format = (unsigned long)_XawTextFormat(ctx);
   2028 
   2029 	rbuf = _XawTextGetText(ctx, left, left + rlen);
   2030 
   2031 	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
   2032 	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
   2033 	    block.ptr = lbuf;
   2034 	    block.length = (int)llen;
   2035 	    _XawTextReplace(ctx, left, left + rlen, &block);
   2036 
   2037 	    src->textSrc.undo_state = False;
   2038 	    block.ptr = rbuf;
   2039 	    block.length = (int)rlen;
   2040 	    _XawTextReplace(ctx, left, left + llen, &block);
   2041 	}
   2042 	else
   2043 	    src->textSrc.undo_state = False;
   2044 	XtFree(rbuf);
   2045     }
   2046     if (undo) {
   2047 	src->textSrc.undo_state = False;
   2048 	if (freepos) {
   2049 	    for (i = 0; i < num_pos; i++) {
   2050 		TextWidget tw = (TextWidget)src->textSrc.text[i];
   2051 		tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
   2052 	    }
   2053 	    XawStackFree(pos, buf);
   2054 	}
   2055 	if (ptr)
   2056 	    XtFree(ptr);
   2057     }
   2058 
   2059     return (result);
   2060 }
   2061 
   2062 static int
   2063 DoFormatText(TextWidget ctx, XawTextPosition left, Bool force, int level,
   2064 	     XawTextBlock *save, XawTextPosition *pos, int num_pos,
   2065 	     Bool paragraph)
   2066 {
   2067     XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
   2068 				    XawsdRight, 1, False);
   2069     XawTextPosition position, tmp, ipos;
   2070     XawTextBlock block, text;
   2071     char buf[128];
   2072     wchar_t *wptr;
   2073     int i, count, cpos;
   2074     Bool done, force2 = force, recurse = False;
   2075 
   2076     position = XawTextSourceRead(ctx->text.source, left, &block, (int)(right - left));
   2077     if (block.length == 0 || left >= right ||
   2078 	(level == 1 && ((XawTextFormat(ctx, XawFmt8Bit) &&
   2079 	 block.ptr[0] != ' ' &&
   2080 	 block.ptr[0] != '\t' &&
   2081 	 !isalnum(*(unsigned char*)block.ptr)) ||
   2082 	(XawTextFormat(ctx, XawFmtWide) &&
   2083 	 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
   2084 	 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
   2085 	 !iswalnum((wint_t)*(wchar_t*)block.ptr)))))
   2086 	return (XawEditDone);
   2087 
   2088     if (level == 1 && !paragraph) {
   2089 	tmp = ctx->text.lastPos;
   2090 	if (Untabify(ctx, left, right, pos, num_pos, save) == False)
   2091 	    return (XawEditError);
   2092 	right += ctx->text.lastPos - tmp;
   2093 	position = XawTextSourceRead(ctx->text.source, left, &block,
   2094 				     (int)(right - left));
   2095     }
   2096 
   2097     text.firstPos = 0;
   2098     text.format = XawFmt8Bit;
   2099 
   2100     ipos = ctx->text.insertPos;
   2101     count = 0;
   2102     done = False;
   2103     while (!done) {
   2104 	if (XawTextFormat(ctx, XawFmt8Bit)) {
   2105 	    for (i = 0; i < block.length; i++)
   2106 		if (block.ptr[i] == ' ')
   2107 		    ++count;
   2108 		else {
   2109 		    done = True;
   2110 		    break;
   2111 		}
   2112 	}
   2113 	else {
   2114 	    wptr = (wchar_t*)block.ptr;
   2115 	    for (i = 0; i < block.length; i++)
   2116 		if (wptr[i] == _Xaw_atowc(' '))
   2117 		    ++count;
   2118 		else {
   2119 		    done = True;
   2120 		    break;
   2121 		}
   2122 	}
   2123 	tmp = position;
   2124 	position = XawTextSourceRead(ctx->text.source, position,
   2125 				     &block, (int)(right - position));
   2126 	if (tmp == position)
   2127 	    done = True;
   2128     }
   2129     position = left + count;
   2130     if (count < ctx->text.left_column) {
   2131 	int bytes = ctx->text.left_column - count;
   2132 
   2133 	text.ptr = XawStackAlloc((unsigned)bytes, buf);
   2134 	text.length = bytes;
   2135 	for (i = 0; i < bytes; i++)
   2136 	    text.ptr[i] = ' ';
   2137 	CHECK_SAVE();
   2138 	if (_XawTextReplace(ctx, left, left, &text)) {
   2139 	    XawStackFree(text.ptr, buf);
   2140 	    return (XawEditError);
   2141 	}
   2142 	XawStackFree(text.ptr, buf);
   2143 	right += bytes;
   2144 	if (num_pos) {
   2145 	    for (cpos = 0; cpos < num_pos; cpos++)
   2146 		if (pos[cpos] >= left)
   2147 		    pos[cpos] += bytes;
   2148 	}
   2149 	if (ipos >= left)
   2150 	    ipos += bytes;
   2151 	count += bytes;
   2152     }
   2153 
   2154     done = False;
   2155     if (!paragraph && level == 1
   2156 	&& ipos <= right && ipos - left > ctx->text.right_column) {
   2157 	XawTextPosition len = ctx->text.lastPos;
   2158 	int skip = ctx->text.justify == XawjustifyRight
   2159 		|| ctx->text.justify == XawjustifyCenter ?
   2160 		ctx->text.left_column : count;
   2161 
   2162 	if (pos)
   2163 	    for (i = 0; i < num_pos; i++)
   2164 		if (pos[i] == ipos)
   2165 		    break;
   2166 
   2167 	StripSpaces(ctx, left + skip, right, pos, num_pos, save);
   2168 	right += ctx->text.lastPos - len;
   2169 	if (pos && i < num_pos)
   2170 	    ipos = pos[i];
   2171 	else
   2172 	    ipos = ctx->text.insertPos;
   2173 	done = ipos - left > ctx->text.right_column;
   2174 	count = skip + (count == skip + 1);
   2175     }
   2176     if ((paragraph || done) && right - left > ctx->text.right_column) {
   2177 	position = tmp = right;
   2178 	XawTextSourceRead(ctx->text.source, position - 1, &block, 1);
   2179 	if (block.length &&
   2180 	    ((XawTextFormat(ctx, XawFmt8Bit) &&
   2181 	     block.ptr[0] == ' ') ||
   2182 	    (XawTextFormat(ctx, XawFmtWide) &&
   2183 	     _Xaw_atowc(XawSP) == *(wchar_t*)block.ptr)))
   2184 	    --position;
   2185 	while (position - left > ctx->text.right_column) {
   2186 	    tmp = position;
   2187 	    position = SrcScan(ctx->text.source, position,
   2188 			       XawstWhiteSpace, XawsdLeft, 1, True);
   2189 	}
   2190 	if (position <= left + ctx->text.left_column)
   2191 	    position = tmp;
   2192 	if (position > left && position - left > ctx->text.left_column
   2193 	    && position != right) {
   2194 	    text.ptr = (char*)"\n";
   2195 	    text.length = 1;
   2196 	    CHECK_SAVE();
   2197 	    if (_XawTextReplace(ctx, position, position + 1, &text))
   2198 		return (XawEditError);
   2199 	    right = position;
   2200 	    recurse = True;
   2201 	    force = True;
   2202 	}
   2203     }
   2204 
   2205     if (force) {
   2206 	if (ctx->text.justify == XawjustifyCenter)
   2207 	    count = ctx->text.right_column - (count - ctx->text.left_column);
   2208 	else
   2209 	    count = ctx->text.right_column;
   2210 	if (count > right - left)
   2211 	    count = (int)(count - (right - left));
   2212 	else
   2213 	    count = 0;
   2214     }
   2215     else
   2216 	count = 0;
   2217     if (count > 0) {
   2218 	switch (ctx->text.justify) {
   2219 	    case XawjustifyLeft:
   2220 		break;
   2221 	    case XawjustifyRight:
   2222 	    case XawjustifyCenter:
   2223 		if (ctx->text.justify == XawjustifyCenter) {
   2224 		    int alnum = 0;
   2225 
   2226 		    if (!(count & 1)) {
   2227 			XawTextSourceRead(ctx->text.source, right, &block, 1);
   2228 			if ((XawTextFormat(ctx, XawFmt8Bit)
   2229 			     && isalnum(*(unsigned char*)block.ptr)) ||
   2230 			    (XawTextFormat(ctx, XawFmtWide)
   2231 			     && iswalnum((wint_t)*(wchar_t*)block.ptr)))
   2232 			    alnum = 1;
   2233 		    }
   2234 		    count = (count + alnum) >> 1;
   2235 		}
   2236 		text.ptr = XawStackAlloc((unsigned)count, buf);
   2237 		text.length = count;
   2238 		for (i = 0; i < count; i++)
   2239 		    text.ptr[i] = ' ';
   2240 		CHECK_SAVE();
   2241 		if (_XawTextReplace(ctx, left, left, &text)) {
   2242 		    XawStackFree(text.ptr, buf);
   2243 		    return (XawEditError);
   2244 		}
   2245 		XawStackFree(text.ptr, buf);
   2246 		position += count;
   2247 		if (num_pos) {
   2248 		    for (cpos = 0; cpos < num_pos; cpos++)
   2249 			if (pos[cpos] > left)
   2250 			    pos[cpos] += count;
   2251 		}
   2252 		else if (ipos > left)
   2253 		    ipos += count;
   2254 		break;
   2255 	    case XawjustifyFull:
   2256 		i = 0;
   2257 		tmp = left;
   2258 		/*CONSTCOND*/
   2259 		while (True) {
   2260 		    tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
   2261 				  XawsdRight, 1, True);
   2262 		    if (tmp < right)
   2263 			++i;
   2264 		    else
   2265 			break;
   2266 		}
   2267 		if (i) {
   2268 		    double inc, ii;
   2269 		    int bytes, steps;
   2270 
   2271 		    bytes = count;
   2272 		    inc = ii = (count + .5) / (double)i;
   2273 
   2274 		    steps = count;
   2275 		    text.ptr = XawStackAlloc((unsigned)steps, buf);
   2276 		    for (i = 0; i < steps; i++)
   2277 			text.ptr[i] = ' ';
   2278 		    tmp = left;
   2279 		    CHECK_SAVE();
   2280 		    while (bytes) {
   2281 			steps = 1;
   2282 			while (inc + ii < 1) {
   2283 			    ++steps;
   2284 			    inc += ii;
   2285 			}
   2286 			tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
   2287 				      XawsdRight, steps, True);
   2288 			if (bytes > inc)
   2289 			    text.length = (int)inc;
   2290 			else
   2291 			    text.length = bytes;
   2292 			bytes -= text.length;
   2293 			if (_XawTextReplace(ctx, tmp, tmp, &text)) {
   2294 			    XawStackFree(text.ptr, buf);
   2295 			    return (XawEditError);
   2296 			}
   2297 			if (num_pos) {
   2298 			    for (cpos = 0; cpos < num_pos; cpos++)
   2299 				if (tmp <= pos[cpos])
   2300 				    pos[cpos] += text.length;
   2301 			}
   2302 			else if (tmp <= ipos)
   2303 			    ipos += text.length;
   2304 			inc -= (int)inc;
   2305 			inc += ii;
   2306 		    }
   2307 		    position += count;
   2308 		    XawStackFree(text.ptr, buf);
   2309 		}
   2310 		break;
   2311 	}
   2312     }
   2313 
   2314     if (!num_pos)
   2315 	ctx->text.insertPos = XawMin(ipos, ctx->text.lastPos);
   2316 
   2317     return (recurse ? DoFormatText(ctx, position + 1,
   2318 				   ctx->text.justify != XawjustifyFull
   2319 				   && (force2 || paragraph),
   2320 				   ++level, save, pos, num_pos, paragraph)
   2321 		 : XawEditDone);
   2322 }
   2323 #undef CHECK_SAVE
   2324 
   2325 /*ARGSUSED*/
   2326 static void
   2327 Indent(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   2328 {
   2329     TextWidget ctx = (TextWidget)w;
   2330     TextSrcObject src = (TextSrcObject)ctx->text.source;
   2331     XawTextPosition from, to, tmp, end = 0, *pos, *posbuf[32];
   2332     XawTextBlock text;
   2333     int i, spaces = MULT(ctx);
   2334     char *lbuf = NULL, *rbuf;
   2335     unsigned llen = 0;
   2336     Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
   2337     Bool format = ctx->text.auto_fill
   2338 	&& ctx->text.left_column < ctx->text.right_column;
   2339 
   2340     text.firstPos = 0;
   2341     text.format = XawFmt8Bit;
   2342     text.ptr = (char*)"";
   2343 
   2344     StartAction(ctx, event);
   2345 
   2346     pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, posbuf);
   2347     for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
   2348 	pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
   2349 
   2350     if (!GetBlockBoundaries(ctx, &from, &to)) {
   2351 	EndAction(ctx);
   2352 	XawStackFree(pos, posbuf);
   2353 	return;
   2354     }
   2355 
   2356     if (undo) {
   2357 	llen = (unsigned)(to - from);
   2358 	end = ctx->text.lastPos;
   2359 	lbuf = _XawTextGetText(ctx, from, to);
   2360 	src->textSrc.undo_state = True;
   2361     }
   2362 
   2363     tmp = ctx->text.lastPos;
   2364     if (!Untabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL)) {
   2365 	XBell(XtDisplay(ctx), 0);
   2366 	EndAction(ctx);
   2367 	XawStackFree(pos, posbuf);
   2368 	if (undo) {
   2369 	    src->textSrc.undo_state = True;
   2370 	    XtFree(lbuf);
   2371 	}
   2372 	return;
   2373     }
   2374     to += ctx->text.lastPos - tmp;
   2375 
   2376     tmp = from;
   2377 
   2378     if (spaces > 0) {
   2379 	char buf[32];
   2380 
   2381 	text.ptr = XawStackAlloc((unsigned)spaces, buf);
   2382 	for (i = 0; i < spaces; i++)
   2383 	    text.ptr[i] = ' ';
   2384 
   2385 	text.length = spaces;
   2386 	while (tmp < to) {
   2387 	    _XawTextReplace(ctx, tmp, tmp, &text);
   2388 
   2389 	    for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
   2390 		if (tmp < pos[i])
   2391 		    pos[i] += spaces;
   2392 
   2393 	    to += spaces;
   2394 	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
   2395 	}
   2396 	XawStackFree(text.ptr, buf);
   2397     }
   2398     else {
   2399 	int min = 32767;
   2400 
   2401 	text.length = 0;
   2402 	tmp = from;
   2403 
   2404 	/* find the amount of spaces to cut */
   2405 	while (tmp < to) {
   2406 	    (void)BlankLine(w, tmp, &i);
   2407 	    if (i < min)
   2408 		min = i;
   2409 	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
   2410 	}
   2411 	spaces = XawMin(-spaces, min);
   2412 
   2413 	/* cut the spaces */
   2414 	tmp = from;
   2415 	while (tmp < to) {
   2416 	    _XawTextReplace(ctx, tmp, tmp + spaces, &text);
   2417 
   2418 	    for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
   2419 		if (tmp < pos[i]) {
   2420 		    if (tmp + spaces < pos[i])
   2421 			pos[i] -= spaces;
   2422 		    else
   2423 			pos[i] = tmp;
   2424 		}
   2425 
   2426 	    to -= spaces;
   2427 	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
   2428 	}
   2429     }
   2430 
   2431     if (!format)
   2432 	Tabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL);
   2433 
   2434     if (undo) {
   2435 	unsigned rlen = (unsigned)(llen + (ctx->text.lastPos - end));
   2436 	unsigned size;
   2437 
   2438 	rbuf = _XawTextGetText(ctx, from, from + rlen);
   2439 
   2440 	text.format = (unsigned long)_XawTextFormat(ctx);
   2441 	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
   2442 	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
   2443 	    text.ptr = lbuf;
   2444 	    text.length = (int)llen;
   2445 	    _XawTextReplace(ctx, from, from + rlen, &text);
   2446 
   2447 	    src->textSrc.undo_state = False;
   2448 	    text.ptr = rbuf;
   2449 	    text.length = (int)rlen;
   2450 	    _XawTextReplace(ctx, from, from + llen, &text);
   2451 	}
   2452 	else
   2453 	    src->textSrc.undo_state = False;
   2454 	XtFree(lbuf);
   2455 	XtFree(rbuf);
   2456     }
   2457 
   2458     for (i = 0; (Cardinal)i < src->textSrc.num_text; i++) {
   2459 	TextWidget tw = (TextWidget)src->textSrc.text[i];
   2460 
   2461 	tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
   2462     }
   2463     XawStackFree(pos, posbuf);
   2464     ctx->text.showposition = True;
   2465 
   2466     EndAction(ctx);
   2467 }
   2468 
   2469 /*ARGSUSED*/
   2470 static void
   2471 ToggleOverwrite(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   2472 {
   2473     TextWidget ctx = (TextWidget)w;
   2474 
   2475     ctx->text.overwrite = !ctx->text.overwrite;
   2476 
   2477     /* call information callback */
   2478     _XawTextSetLineAndColumnNumber(ctx, True);
   2479 }
   2480 #endif /* OLDXAW */
   2481 
   2482 /*
   2483  * Insertion Routines
   2484  */
   2485 static int
   2486 InsertNewLineAndBackupInternal(TextWidget ctx)
   2487 {
   2488     int count, error = XawEditDone, mult = MULT(ctx);
   2489 #ifndef OLDXAW
   2490     XawTextPosition position;
   2491 #endif
   2492     XawTextBlock text;
   2493     char buf[32];
   2494 
   2495     if (mult < 0) {
   2496 	ctx->text.mult = 1;
   2497 	return (XawEditError);
   2498     }
   2499 
   2500     text.format = (unsigned long)_XawTextFormat(ctx);
   2501     text.length = mult;
   2502     text.firstPos = 0;
   2503 
   2504     if (text.format == XawFmtWide) {
   2505 	wchar_t *wptr;
   2506 
   2507 	text.ptr = (XawStackAlloc(sizeof(wchar_t) * (size_t)mult, buf));
   2508 	wptr = (wchar_t *)text.ptr;
   2509 	for (count = 0; count < mult; count++)
   2510 	    wptr[count] = _Xaw_atowc(XawLF);
   2511     }
   2512     else {
   2513 	text.ptr = (XawStackAlloc(sizeof(char) * (size_t)mult, buf));
   2514 	for (count = 0; count < mult; count++)
   2515 	    text.ptr[count] = XawLF;
   2516     }
   2517 
   2518 #ifndef OLDXAW
   2519     position = SrcScan(ctx->text.source, ctx->text.insertPos,
   2520 		       XawstEOL, XawsdLeft, 1, False);
   2521 #endif
   2522     if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
   2523 	XBell( XtDisplay(ctx), 50);
   2524 	error = XawEditError;
   2525     }
   2526     else {
   2527 	ctx->text.showposition = TRUE;
   2528 	ctx->text.insertPos += text.length;
   2529     }
   2530 
   2531     XawStackFree(text.ptr, buf);
   2532 
   2533 #ifndef OLDXAW
   2534     if (ctx->text.auto_fill && error == XawEditDone)
   2535 	(void)FormatText(ctx, position, ctx->text.justify != XawjustifyFull,
   2536 			 NULL, 0);
   2537 #endif
   2538 
   2539     return (error);
   2540 }
   2541 
   2542 /*ARGSUSED*/
   2543 static void
   2544 InsertNewLineAndBackup(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   2545 {
   2546     TextWidget ctx = (TextWidget)w;
   2547     XawTextPosition insertPos = ctx->text.insertPos;
   2548 
   2549     StartAction((TextWidget)w, event);
   2550     (void)InsertNewLineAndBackupInternal(ctx);
   2551     ctx->text.insertPos = SrcScan(ctx->text.source, insertPos, XawstEOL,
   2552 				  XawsdRight, 1, False);
   2553     EndAction((TextWidget)w);
   2554 }
   2555 
   2556 static int
   2557 LocalInsertNewLine(TextWidget ctx, XEvent *event)
   2558 {
   2559     int error;
   2560 
   2561     StartAction(ctx, event);
   2562     error = InsertNewLineAndBackupInternal(ctx);
   2563     ctx->text.from_left = -1;
   2564     EndAction(ctx);
   2565 
   2566     return (error);
   2567 }
   2568 
   2569 /*ARGSUSED*/
   2570 static void
   2571 InsertNewLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   2572 {
   2573     (void)LocalInsertNewLine((TextWidget)w, event);
   2574 }
   2575 
   2576 /*ARGSUSED*/
   2577 static void
   2578 InsertNewLineAndIndent(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   2579 {
   2580     XawTextBlock text;
   2581     XawTextPosition pos1;
   2582     int length;
   2583     TextWidget ctx = (TextWidget)w;
   2584     char * line_to_ip;
   2585 
   2586     StartAction(ctx, event);
   2587     pos1 = SrcScan(ctx->text.source, ctx->text.insertPos,
   2588 		   XawstEOL, XawsdLeft, 1, False);
   2589 
   2590     line_to_ip = _XawTextGetText(ctx, pos1, ctx->text.insertPos);
   2591 
   2592     text.format = (unsigned long)_XawTextFormat(ctx);
   2593     text.firstPos = 0;
   2594 
   2595     if (text.format == XawFmtWide) {
   2596 	wchar_t *ptr;
   2597 
   2598 	text.ptr = XtMalloc((Cardinal)((2 + wcslen((wchar_t*)line_to_ip))
   2599 			    * sizeof(wchar_t)));
   2600 	ptr = (wchar_t*)text.ptr;
   2601 	ptr[0] = _Xaw_atowc(XawLF);
   2602 	wcscpy((wchar_t*)++ptr, (wchar_t*)line_to_ip);
   2603 
   2604 	length = (int)wcslen((wchar_t*)text.ptr);
   2605 	while (length && (iswspace(*ptr) || *ptr == _Xaw_atowc(XawTAB)))
   2606 	  ptr++, length--;
   2607 	*ptr = (wchar_t)0;
   2608 	text.length = (int)wcslen((wchar_t*)text.ptr);
   2609     }
   2610     else {
   2611 	char *ptr;
   2612 
   2613 	length = (int)strlen(line_to_ip);
   2614 	text.ptr = XtMalloc((Cardinal)((size_t)(2 + length) * sizeof(char)));
   2615 	ptr = text.ptr;
   2616 	ptr[0] = XawLF;
   2617 	strcpy(++ptr, line_to_ip);
   2618 
   2619 	length++;
   2620 	while (length && (isspace((unsigned char)*ptr) || (*ptr == XawTAB)))
   2621 	    ptr++, length--;
   2622 	*ptr = '\0';
   2623 	text.length = (int)strlen(text.ptr);
   2624     }
   2625     XtFree(line_to_ip);
   2626 
   2627     if (_XawTextReplace(ctx,ctx->text.insertPos, ctx->text.insertPos, &text)) {
   2628 	XBell(XtDisplay(ctx), 50);
   2629 	XtFree(text.ptr);
   2630 	EndAction(ctx);
   2631 	return;
   2632     }
   2633 
   2634     XtFree(text.ptr);
   2635     ctx->text.from_left = -1;
   2636     ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
   2637 				  XawstPositions, XawsdRight, text.length, True);
   2638     EndAction(ctx);
   2639 }
   2640 
   2641 /*
   2642  * Selection Routines
   2643  */
   2644 static void
   2645 SelectWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2646 {
   2647     TextWidget ctx = (TextWidget)w;
   2648     XawTextPosition l, r;
   2649 
   2650     StartAction(ctx, event);
   2651     l = SrcScan(ctx->text.source, ctx->text.insertPos,
   2652 		XawstWhiteSpace, XawsdLeft, 1, False);
   2653     r = SrcScan(ctx->text.source, l, XawstWhiteSpace, XawsdRight, 1, False);
   2654     _XawTextSetSelection(ctx, l, r, params, *num_params);
   2655     EndAction(ctx);
   2656 }
   2657 
   2658 static void
   2659 SelectAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2660 {
   2661     TextWidget ctx = (TextWidget)w;
   2662 
   2663     StartAction(ctx, event);
   2664     _XawTextSetSelection(ctx,zeroPosition,ctx->text.lastPos,params,*num_params);
   2665     EndAction(ctx);
   2666 }
   2667 
   2668 static void
   2669 ModifySelection(TextWidget ctx, XEvent *event,
   2670 		XawTextSelectionMode mode,
   2671 		XawTextSelectionAction action,
   2672 		String *params, Cardinal *num_params)
   2673 {
   2674 #ifndef OLDXAW
   2675     int old_y = ctx->text.ev_y;
   2676 #endif
   2677 
   2678     StartAction(ctx, event);
   2679     NotePosition(ctx, event);
   2680 
   2681 #ifndef OLDXAW
   2682     if (event->type == MotionNotify) {
   2683 	if (ctx->text.ev_y <= ctx->text.margin.top) {
   2684 	    if (old_y >= ctx->text.ev_y)
   2685 		XawTextScroll(ctx, -1, 0);
   2686 	}
   2687 	else if (ctx->text.ev_y >= XtHeight(ctx) - ctx->text.margin.bottom) {
   2688 	    if (old_y <= ctx->text.ev_y
   2689 		&& !IsPositionVisible(ctx, ctx->text.lastPos))
   2690 	      XawTextScroll(ctx, 1, 0);
   2691 	}
   2692     }
   2693 #endif
   2694     ctx->text.from_left = -1;
   2695     _XawTextAlterSelection(ctx, mode, action, params, num_params);
   2696 
   2697     EndAction(ctx);
   2698 }
   2699 
   2700 static void
   2701 SelectStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2702 {
   2703     TextWidget ctx = (TextWidget)w;
   2704 
   2705 #ifndef OLDXAW
   2706     if (!ctx->text.selection_state) {
   2707 	ctx->text.selection_state = True;
   2708 #endif
   2709 	ModifySelection(ctx, event,
   2710 			XawsmTextSelect, XawactionStart, params, num_params);
   2711 #ifndef OLDXAW
   2712     }
   2713 #endif
   2714 }
   2715 
   2716 static void
   2717 SelectAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2718 {
   2719     TextWidget ctx = (TextWidget)w;
   2720 
   2721 #ifndef OLDXAW
   2722     if (ctx->text.selection_state)
   2723 #endif
   2724 	ModifySelection(ctx, event,
   2725 			XawsmTextSelect, XawactionAdjust, params, num_params);
   2726 }
   2727 
   2728 static void
   2729 SelectEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2730 {
   2731     TextWidget ctx = (TextWidget)w;
   2732 
   2733 #ifndef OLDXAW
   2734     if (ctx->text.selection_state) {
   2735 	ctx->text.selection_state = False;
   2736 #endif
   2737 	ModifySelection(ctx, event,
   2738 			XawsmTextSelect, XawactionEnd, params, num_params);
   2739 #ifndef OLDXAW
   2740     }
   2741 #endif
   2742 }
   2743 
   2744 static void
   2745 ExtendStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2746 {
   2747     TextWidget ctx = (TextWidget)w;
   2748 
   2749 #ifndef OLDXAW
   2750     if (!ctx->text.selection_state) {
   2751 	ctx->text.selection_state = True;
   2752 #endif
   2753 	ModifySelection(ctx, event,
   2754 			XawsmTextExtend, XawactionStart, params, num_params);
   2755 #ifndef OLDXAW
   2756     }
   2757 #endif
   2758 }
   2759 
   2760 static void
   2761 ExtendAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2762 {
   2763     TextWidget ctx = (TextWidget)w;
   2764 
   2765 #ifndef OLDXAW
   2766     if (ctx->text.selection_state)
   2767 #endif
   2768 	ModifySelection(ctx, event,
   2769 			XawsmTextExtend, XawactionAdjust, params, num_params);
   2770 }
   2771 
   2772 static void
   2773 ExtendEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
   2774 {
   2775     TextWidget ctx = (TextWidget)w;
   2776 
   2777 #ifndef OLDXAW
   2778     if (ctx->text.selection_state) {
   2779 	ctx->text.selection_state = False;
   2780 #endif
   2781 	ModifySelection(ctx, event,
   2782 			XawsmTextExtend, XawactionEnd, params, num_params);
   2783 #ifndef OLDXAW
   2784     }
   2785 #endif
   2786 }
   2787 
   2788 static void
   2789 SelectSave(Widget  w, XEvent *event, String *params, Cardinal *num_params)
   2790 {
   2791     int num_atoms, n;
   2792     Atom *sel;
   2793     Display *dpy = XtDisplay(w);
   2794     Atom selections[256];
   2795 
   2796     StartAction((TextWidget)w, event);
   2797     num_atoms = (int)*num_params;
   2798     if (num_atoms > 256)
   2799 	num_atoms = 256;
   2800     for (sel = selections, n = 0; n < num_atoms; n++, sel++, params++)
   2801 	*sel = XInternAtom(dpy, *params, False);
   2802     _XawTextSaltAwaySelection((TextWidget)w, selections, num_atoms);
   2803     EndAction((TextWidget)w);
   2804 }
   2805 
   2806 /*
   2807  * Misc. Routines
   2808  */
   2809 /*ARGSUSED*/
   2810 static void
   2811 SetKeyboardFocus(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   2812 {
   2813     Widget shell, parent;
   2814 
   2815     shell = parent = w;
   2816     while (parent) {
   2817 	if (XtIsShell(shell = parent))
   2818 	    break;
   2819 	parent = XtParent(parent);
   2820     }
   2821     XtSetKeyboardFocus(shell, w);
   2822 }
   2823 
   2824 /*ARGSUSED*/
   2825 static void
   2826 RedrawDisplay(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   2827 {
   2828     StartAction((TextWidget)w, event);
   2829     _XawTextClearAndCenterDisplay((TextWidget)w);
   2830     EndAction((TextWidget)w);
   2831 }
   2832 
   2833 /* This is kind of a hack, but, only one text widget can have focus at
   2834  * a time on one display. There is a problem in the implementation of the
   2835  * text widget, the scrollbars can not be addressed via editres, since they
   2836  * are not children of a subclass of composite.
   2837  * The focus variable is required to make sure only one text window will
   2838  * show a block cursor at one time.
   2839  */
   2840 struct _focus { Display *display; Widget widget; };
   2841 static struct _focus *focus;
   2842 static Cardinal num_focus;
   2843 
   2844 /*ARGSUSED*/
   2845 static void
   2846 DestroyFocusCallback(Widget w, XtPointer user_data, XtPointer call_data _X_UNUSED)
   2847 {
   2848     struct _focus *f = (struct _focus*)(user_data);
   2849 
   2850     if (f->widget == w)
   2851 	f->widget = NULL;
   2852 }
   2853 
   2854 /*ARGSUSED*/
   2855 static void
   2856 TextFocusIn(Widget w, XEvent *event, String *p, Cardinal *n)
   2857 {
   2858     TextWidget ctx = (TextWidget)w;
   2859     Bool display_caret = ctx->text.display_caret;
   2860     int i;
   2861 
   2862     if (event->xfocus.detail == NotifyPointer)
   2863 	return;
   2864 
   2865     if (event->xfocus.send_event) {
   2866 	Window root, child;
   2867 	int rootx, rooty, x, y;
   2868 	unsigned int mask;
   2869 
   2870 	if (ctx->text.hasfocus)
   2871 	    return;
   2872 
   2873 	if (XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
   2874 			  &rootx, &rooty, &x, &y, &mask)) {
   2875 	    if (child)
   2876 		return;
   2877 	}
   2878     }
   2879 
   2880     /* Let the input method know focus has arrived. */
   2881     _XawImSetFocusValues(w, NULL, 0);
   2882 
   2883     if (display_caret)
   2884 	StartAction(ctx, event);
   2885     ctx->text.hasfocus = TRUE;
   2886     if (display_caret)
   2887 	EndAction(ctx);
   2888 
   2889     for (i = 0; (Cardinal)i < num_focus; i++)
   2890 	if (focus[i].display == XtDisplay(w))
   2891 	    break;
   2892     if ((Cardinal)i >= num_focus) {
   2893 	focus = (struct _focus*)
   2894 	    XtRealloc((XtPointer)focus, (Cardinal)(sizeof(struct _focus) * (num_focus + 1)));
   2895 	i = (int)num_focus;
   2896 	focus[i].widget = NULL;
   2897 	focus[i].display = XtDisplay(w);
   2898 	num_focus++;
   2899     }
   2900     if (focus[i].widget != w) {
   2901 	Widget old = focus[i].widget;
   2902 
   2903 	focus[i].widget = w;
   2904 	if (old != NULL) {
   2905 	    TextFocusOut(old, event, p, n);
   2906 	    /* TextFocusOut may set it to NULL */
   2907 	    focus[i].widget = w;
   2908 	}
   2909 	XtAddCallback(w, XtNdestroyCallback,
   2910 		      DestroyFocusCallback, (XtPointer)&focus[i]);
   2911     }
   2912 }
   2913 
   2914 /*ARGSUSED*/
   2915 static void
   2916 TextFocusOut(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   2917 {
   2918     TextWidget ctx = (TextWidget)w;
   2919     Bool display_caret = ctx->text.display_caret;
   2920     Widget shell;
   2921     Window window;
   2922     int i, revert;
   2923 
   2924     shell = w;
   2925     while (shell) {
   2926 	if (XtIsShell(shell))
   2927 	   break;
   2928 	shell = XtParent(shell);
   2929     }
   2930 
   2931     for (i = 0; (Cardinal)i < num_focus; i++)
   2932 	if (focus[i].display == XtDisplay(w))
   2933 	    break;
   2934     XGetInputFocus(XtDisplay(w), &window, &revert);
   2935     if ((XtWindow(shell) == window &&
   2936 	 ((Cardinal)i < num_focus && focus[i].widget == w))
   2937 	 || event->xfocus.detail == NotifyPointer)
   2938 	return;
   2939 
   2940     if ((Cardinal)i < num_focus && focus[i].widget) {
   2941 	XtRemoveCallback(focus[i].widget, XtNdestroyCallback,
   2942 			 DestroyFocusCallback, (XtPointer)&focus[i]);
   2943 	focus[i].widget = NULL;
   2944     }
   2945 
   2946     /* Let the input method know focus has left.*/
   2947     _XawImUnsetFocus(w);
   2948 
   2949     if (display_caret)
   2950 	StartAction(ctx, event);
   2951     ctx->text.hasfocus = FALSE;
   2952     if (display_caret)
   2953 	EndAction(ctx);
   2954 }
   2955 
   2956 /*ARGSUSED*/
   2957 static void
   2958 TextEnterWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   2959 {
   2960     TextWidget ctx = (TextWidget)w;
   2961 
   2962     if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
   2963 	&& !ctx->text.hasfocus)
   2964 	_XawImSetFocusValues(w, NULL, 0);
   2965 }
   2966 
   2967 /*ARGSUSED*/
   2968 static void
   2969 TextLeaveWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   2970 {
   2971     TextWidget ctx = (TextWidget)w;
   2972 
   2973     if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
   2974 	&& !ctx->text.hasfocus)
   2975 	_XawImUnsetFocus(w);
   2976 }
   2977 
   2978 /*
   2979  * Function:
   2980  *	AutoFill
   2981  *	Arguments: ctx - The text widget.
   2982  *
   2983  * Description:
   2984  *	  Breaks the line at the previous word boundary when
   2985  *	called inside InsertChar.
   2986  */
   2987 static void
   2988 AutoFill(TextWidget ctx)
   2989 {
   2990     int width, height, x, line_num, max_width;
   2991     XawTextPosition ret_pos;
   2992     XawTextBlock text;
   2993     XRectangle cursor;
   2994     wchar_t wc_buf[2];
   2995 
   2996     for (line_num = 0; line_num < ctx->text.lt.lines ; line_num++)
   2997 	if (ctx->text.lt.info[line_num].position >= ctx->text.insertPos)
   2998 	    break;
   2999     if (line_num)
   3000 	line_num--;		/* backup a line. */
   3001 
   3002     XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
   3003     max_width = Max(0, (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width);
   3004 
   3005     x = ctx->text.r_margin.left;
   3006     XawTextSinkFindPosition(ctx->text.sink, ctx->text.lt.info[line_num].position,
   3007 			    x, max_width, True, &ret_pos,
   3008 			    &width, &height);
   3009 
   3010     if (ret_pos <= ctx->text.lt.info[line_num].position
   3011 	|| ret_pos >= ctx->text.insertPos || ret_pos < 1)
   3012 	return;
   3013 
   3014     XawTextSourceRead(ctx->text.source, ret_pos - 1, &text, 1);
   3015 
   3016     if (XawTextFormat(ctx, XawFmtWide)) {
   3017 	wc_buf[0] = *(wchar_t *)text.ptr;
   3018 	if (wc_buf[0] != _Xaw_atowc(XawSP) && wc_buf[0] != _Xaw_atowc(XawTAB))
   3019 	    /* Only eats white spaces */
   3020 	    return;
   3021 
   3022 	text.format = XawFmtWide;
   3023 	text.ptr = (char *)wc_buf;
   3024 	wc_buf[0] = _Xaw_atowc(XawLF);
   3025 	wc_buf[1] = 0;
   3026     }
   3027     else {
   3028 	if (text.ptr[0] != XawSP && text.ptr[0] != XawTAB)
   3029 	    /* Only eats white spaces */
   3030 	    return;
   3031 
   3032 	text.format = XawFmt8Bit;
   3033 	text.ptr = (char*)"\n";
   3034     }
   3035     text.length = 1;
   3036     text.firstPos = 0;
   3037 
   3038     if (_XawTextReplace(ctx, ret_pos - 1, ret_pos, &text))
   3039 	XBell(XtDisplay((Widget)ctx), 0);
   3040 
   3041     if (++ctx->text.insertPos > ctx->text.lastPos)
   3042 	ctx->text.insertPos = ctx->text.lastPos;
   3043 }
   3044 
   3045 /*ARGSUSED*/
   3046 static void
   3047 InsertChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
   3048 {
   3049     TextWidget ctx = (TextWidget)w;
   3050     char *ptr, strbuf[128], ptrbuf[512];
   3051     int count, error, mult = MULT(ctx);
   3052     KeySym keysym;
   3053     XawTextBlock text;
   3054 #ifndef OLDXAW
   3055     Bool format = False;
   3056 #endif
   3057     XawTextPosition from, to;
   3058 
   3059     if (XtIsSubclass (ctx->text.source, (WidgetClass) multiSrcObjectClass))
   3060 	text.length = _XawImWcLookupString(w, &event->xkey, (wchar_t*)strbuf,
   3061 					   sizeof(strbuf), &keysym);
   3062     else
   3063 	text.length = _XawLookupString(w, (XKeyEvent*)event, strbuf,
   3064 				       sizeof(strbuf), &keysym);
   3065 
   3066     if (text.length == 0)
   3067 	return;
   3068 
   3069     if (mult < 0) {
   3070 	ctx->text.mult = 1;
   3071 	return;
   3072     }
   3073 
   3074     text.format = (unsigned long)_XawTextFormat(ctx);
   3075     if (text.format == XawFmtWide) {
   3076 	text.ptr = ptr = XawStackAlloc(sizeof(wchar_t) * (size_t)text.length
   3077 				       * (size_t)mult, ptrbuf);
   3078 	for (count = 0; count < mult; count++) {
   3079 	    memcpy((char*)ptr, (char *)strbuf, sizeof(wchar_t) * (size_t)text.length);
   3080 	    ptr += sizeof(wchar_t) * (size_t)text.length;
   3081 	}
   3082 #ifndef OLDXAW
   3083 	if (mult == 1)
   3084 	    format = ctx->text.left_column < ctx->text.right_column;
   3085 #endif
   3086     }
   3087     else {	/* == XawFmt8Bit */
   3088 	text.ptr = ptr = XawStackAlloc((unsigned)(text.length * mult), ptrbuf);
   3089 	for (count = 0; count < mult; count++) {
   3090 	    strncpy(ptr, strbuf, (size_t)text.length);
   3091 	    ptr += text.length;
   3092 	}
   3093 #ifndef OLDXAW
   3094 	if (mult == 1)
   3095 	    format = ctx->text.left_column < ctx->text.right_column;
   3096 #endif
   3097     }
   3098 
   3099     text.length = text.length * mult;
   3100     text.firstPos = 0;
   3101 
   3102     StartAction(ctx, event);
   3103 #ifndef OLDXAW
   3104     if (mult == 1)
   3105 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
   3106 #endif
   3107 
   3108     from = ctx->text.insertPos;
   3109 #ifndef OLDXAW
   3110     if (ctx->text.overwrite) {
   3111 	XawTextPosition tmp;
   3112 
   3113 	to = from + mult;
   3114 	tmp = SrcScan(ctx->text.source, from, XawstEOL, XawsdRight, 1, False);
   3115 	if (to > tmp)
   3116 	    to = tmp;
   3117     }
   3118     else
   3119 #endif
   3120 	to = from;
   3121 
   3122     error = _XawTextReplace(ctx, from , to, &text);
   3123 
   3124     if (error == XawEditDone) {
   3125 	ctx->text.from_left = -1;
   3126 	ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
   3127 				      XawstPositions, XawsdRight,
   3128 				      text.length, True);
   3129 	if (ctx->text.auto_fill) {
   3130 #ifndef OLDXAW
   3131 	    if (format)
   3132 		(void)FormatText(ctx, SrcScan(ctx->text.source,
   3133 					      ctx->text.insertPos, XawstEOL,
   3134 					      XawsdLeft, 1, False), False,
   3135 					      NULL, 0);
   3136 	    else
   3137 #endif
   3138 		AutoFill(ctx);
   3139 	}
   3140     }
   3141     else
   3142 	XBell(XtDisplay(ctx), 50);
   3143 
   3144     XawStackFree(text.ptr, ptrbuf);
   3145     EndAction(ctx);
   3146 
   3147     if (error == XawEditDone && text.format == XawFmt8Bit && text.length == 1
   3148 	&& (text.ptr[0] == ')' || text.ptr[0] == ']' || text.ptr[0] == '}')
   3149 	&& ctx->text.display_caret) {
   3150 	static struct timeval tmval = {0, 500000};
   3151 	fd_set fds;
   3152 	Widget source = ctx->text.source;
   3153 	XawTextPosition insertPos = ctx->text.insertPos, pos, tmp, last;
   3154 	char left, right = text.ptr[0];
   3155 	int level = 0;
   3156 	XtAppContext app_context = XtWidgetToApplicationContext(w);
   3157 
   3158 	left = right == ')' ? '(' : right == ']' ? '[' : '{';
   3159 
   3160 	last = insertPos - 1;
   3161 	do {
   3162 	    text.ptr[0] = left;
   3163 	    pos = XawTextSourceSearch(source, last, XawsdLeft, &text);
   3164 	    if (pos == XawTextSearchError || !IsPositionVisible(ctx, pos))
   3165 		return;
   3166 	    text.ptr[0] = right;
   3167 	    tmp = pos;
   3168 	    do {
   3169 		tmp = XawTextSourceSearch(source, tmp, XawsdRight, &text);
   3170 		if (tmp == XawTextSearchError)
   3171 		    return;
   3172 		if (tmp <= last)
   3173 		    ++level;
   3174 	    } while (++tmp <= last);
   3175 	    --level;
   3176 	    last = pos;
   3177 	} while (level);
   3178 
   3179 	StartAction(ctx, NULL);
   3180 #ifndef OLDXAW
   3181 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
   3182 #endif
   3183 	ctx->text.insertPos = pos;
   3184 	EndAction(ctx);
   3185 
   3186 	XSync(XtDisplay(w), False);
   3187 	while (XtAppPending(app_context) & XtIMXEvent) {
   3188 	    XEvent ev;
   3189 	    if (! XtAppPeekEvent(app_context, &ev))
   3190 		break;
   3191 	    if (ev.type == KeyPress || ev.type == ButtonPress)
   3192 		break;
   3193 	    XtAppProcessEvent(app_context, XtIMXEvent);
   3194 	}
   3195 	FD_ZERO(&fds);
   3196 	FD_SET(ConnectionNumber(XtDisplay(w)), &fds);
   3197 	(void)select(FD_SETSIZE, &fds, NULL, NULL, &tmval);
   3198 	if (tmval.tv_usec != 500000)
   3199 	    usleep(40000);
   3200 
   3201 	StartAction(ctx, NULL);
   3202 #ifndef OLDXAW
   3203 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
   3204 #endif
   3205 	ctx->text.insertPos = insertPos;
   3206 	EndAction(ctx);
   3207     }
   3208 }
   3209 
   3210 /* IfHexConvertHexElseReturnParam() - called by InsertString
   3211  *
   3212  * i18n requires the ability to specify multiple characters in a hexa-
   3213  * decimal string at once.  Since Insert was already too long, I made
   3214  * this a separate routine.
   3215  *
   3216  * A legal hex string in MBNF: '0' 'x' ( HEX-DIGIT HEX-DIGIT )+ '\0'
   3217  *
   3218  * WHEN:    the passed param is a legal hex string
   3219  * RETURNS: a pointer to that converted, null terminated hex string;
   3220  *	    len_return holds the character count of conversion result
   3221  *
   3222  * WHEN:    the passed param is not a legal hex string:
   3223  * RETURNS: the parameter passed;
   3224  *	    len_return holds the char count of param.
   3225  *
   3226  * NOTE:    In neither case will there be strings to free. */
   3227 static char *
   3228 IfHexConvertHexElseReturnParam(const char *param, int *len_return)
   3229 {
   3230     const char *p;	/* steps through param char by char */
   3231     char c;		/* holds the character pointed to by p */
   3232     int ind;		/* steps through hexval buffer char by char */
   3233     static char hexval[XawTextActionMaxHexChars];
   3234     Boolean first_digit;
   3235 
   3236     /* reject if it doesn't begin with 0x and at least one more character. */
   3237     if ((param[0] != '0') || (param[1] != 'x') || (param[2] == '\0')) {
   3238 	goto out;
   3239     }
   3240 
   3241     /* Skip the 0x; go character by character shifting and adding. */
   3242     first_digit = True;
   3243     ind = 0;
   3244     hexval[ind] = '\0';
   3245 
   3246     for (p = param+2; (c = *p) != '\0'; p++) {
   3247 	hexval[ind] = (char)(hexval[ind] * 16);
   3248 	if (c >= '0' && c <= '9')
   3249 	    hexval[ind] = (char)(hexval[ind] + (c - '0'));
   3250 	else if (c >= 'a' && c <= 'f')
   3251 	    hexval[ind] = (char)(hexval[ind] + (c - 'a' + 10));
   3252 	else if (c >= 'A' && c <= 'F')
   3253 	    hexval[ind] = (char)(hexval[ind] + (c - 'A' + 10));
   3254 	else
   3255 	    break;
   3256 
   3257 	/* If we didn't break in preceding line, it was a good hex char. */
   3258 	if (first_digit)
   3259 	    first_digit = False;
   3260 	else {
   3261 	    first_digit = True;
   3262 	    if (++ind < XawTextActionMaxHexChars)
   3263 		hexval[ind] = '\0';
   3264 	    else {
   3265 		goto out;
   3266 	    }
   3267 	}
   3268     }
   3269 
   3270     /* We quit the above loop because we hit a non hex.  If that char is \0... */
   3271     if ((c == '\0') && first_digit) {
   3272 	*len_return = (int)strlen(hexval);
   3273 	return (hexval);       /* ...it was a legal hex string, so return it */
   3274     }
   3275 
   3276     /* Else, there were non-hex chars or odd digit count, so... */
   3277 out:
   3278     *len_return = (int)strlen(param);
   3279     return ((char *)param);			   /* ...return the verbatim string. */
   3280 }
   3281 
   3282 /* InsertString() - action
   3283  *
   3284  * Mostly rewritten for R6 i18n.
   3285  *
   3286  * Each parameter, in turn, will be insert at the inputPos
   3287  * and the inputPos advances to the insertion's end.
   3288  *
   3289  * The exception is that parameters composed of the two
   3290  * characters 0x, followed only by an even number of
   3291  * hexadecimal digits will be converted to characters */
   3292 /*ARGSUSED*/
   3293 static void
   3294 InsertString(Widget w, XEvent *event, String *params, Cardinal *num_params)
   3295 {
   3296     TextWidget ctx = (TextWidget)w;
   3297     XtAppContext app_con = XtWidgetToApplicationContext(w);
   3298     XawTextBlock text;
   3299     int i;
   3300 
   3301     text.firstPos = 0;
   3302     text.format = (unsigned long)_XawTextFormat(ctx);
   3303 
   3304     StartAction(ctx, event);
   3305     for (i = (int)*num_params; i; i--, params++) {	/* DO FOR EACH PARAMETER */
   3306 	text.ptr = IfHexConvertHexElseReturnParam((char*) *params, &text.length);
   3307 
   3308 	if (text.length == 0)
   3309 	    continue;
   3310 
   3311 	if (XawTextFormat(ctx, XawFmtWide)) {	/* convert to WC */
   3312 	    int temp_len;
   3313 
   3314 	    text.ptr = (char*)_XawTextMBToWC(XtDisplay(w), text.ptr,
   3315 					     &text.length);
   3316 
   3317 	    if (text.ptr == NULL) {	  /* conversion error */
   3318 		XtAppWarningMsg(app_con,
   3319 				"insertString", "textAction", "XawError",
   3320 				"insert-string()'s parameter contents "
   3321 				"not legal in this locale.",
   3322 				NULL, NULL);
   3323 		ParameterError(w, *params);
   3324 		continue;
   3325 	   }
   3326 
   3327 	    /* Double check that the new input is legal: try to convert to MB. */
   3328 
   3329 	    temp_len = text.length;	 /* _XawTextWCToMB's 3rd arg is in_out */
   3330 	    if (_XawTextWCToMB(XtDisplay(w), (wchar_t*)text.ptr, &temp_len)
   3331 		== NULL) {
   3332 		XtAppWarningMsg( app_con,
   3333 				 "insertString", "textAction", "XawError",
   3334 				 "insert-string()'s parameter contents "
   3335 				 "not legal in this locale.",
   3336 				 NULL, NULL);
   3337 		ParameterError(w, *params);
   3338 		continue;
   3339 	    }
   3340 	} /* convert to WC */
   3341 
   3342 	if (_XawTextReplace(ctx, ctx->text.insertPos,
   3343 			    ctx->text.insertPos, &text)) {
   3344 	    XBell(XtDisplay(ctx), 50);
   3345 	    EndAction(ctx);
   3346 	    return;
   3347 	}
   3348 
   3349 	ctx->text.from_left = -1;
   3350 	/* Advance insertPos to the end of the string we just inserted. */
   3351 	ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
   3352 				       XawstPositions, XawsdRight, text.length,
   3353 				      True);
   3354 
   3355     } /* DO FOR EACH PARAMETER */
   3356 
   3357     EndAction(ctx);
   3358 }
   3359 
   3360 /* DisplayCaret() - action
   3361  *
   3362  * The parameter list should contain one boolean value.  If the
   3363  * argument is true, the cursor will be displayed.  If false, not.
   3364  *
   3365  * The exception is that EnterNotify and LeaveNotify events may
   3366  * have a second argument, "always".  If they do not, the cursor
   3367  * is only affected if the focus member of the event is true.	*/
   3368 static void
   3369 DisplayCaret(Widget w, XEvent *event, String *params, Cardinal *num_params)
   3370 {
   3371     TextWidget ctx = (TextWidget)w;
   3372     Bool display_caret = True;
   3373 
   3374     if	((event->type == EnterNotify || event->type == LeaveNotify)
   3375 	 && ((*num_params >= 2) && (strcmp(params[1], "always") == 0))
   3376 	 && (!event->xcrossing.focus))
   3377 	return;
   3378 
   3379     if (*num_params > 0) {	/* default arg is "True" */
   3380 	XrmValue from, to;
   3381 	from.size = (unsigned)strlen(from.addr = (char*)params[0]);
   3382 	XtConvert(w, XtRString, &from, XtRBoolean, &to);
   3383 
   3384 	if (to.addr != NULL)
   3385 	    display_caret = *(Boolean*)to.addr;
   3386 	if (ctx->text.display_caret == display_caret)
   3387 	    return;
   3388     }
   3389     StartAction(ctx, event);
   3390     ctx->text.display_caret = (Boolean)display_caret;
   3391     EndAction(ctx);
   3392 }
   3393 
   3394 #ifndef OLDXAW
   3395 static void
   3396 Numeric(Widget w, XEvent *event, String *params, Cardinal *num_params)
   3397 {
   3398     TextWidget ctx = (TextWidget)w;
   3399 
   3400     if (ctx->text.numeric) {
   3401 	long mult = ctx->text.mult;
   3402 
   3403 	if (*num_params != 1 || strlen(params[0]) != 1
   3404 	    || (!isdigit((unsigned char)params[0][0])
   3405 		&& (params[0][0] != '-' || mult != 0))) {
   3406 	    char err_buf[256];
   3407 
   3408 	    if (event && (event->type == KeyPress || event->type == KeyRelease)
   3409 		&& params[0][0] == '-') {
   3410 		InsertChar(w, event, params, num_params);
   3411 		return;
   3412 	    }
   3413 	    snprintf(err_buf, sizeof(err_buf),
   3414 		     "numeric: Invalid argument%s'%s'",
   3415 		     *num_params ? ", " : "",
   3416 		     *num_params ? params[0] : "");
   3417 	    XtAppWarning(XtWidgetToApplicationContext(w), err_buf);
   3418 	    ctx->text.numeric = False;
   3419 	    ctx->text.mult = 1;
   3420 	    return;
   3421 	}
   3422 	if (params[0][0] == '-') {
   3423 	    ctx->text.mult = 32767;
   3424 	    return;
   3425 	}
   3426 	else if (mult == 32767) {
   3427 	    return;
   3428 	}
   3429 	else {
   3430 	    mult = mult * 10 + (params[0][0] - '0') * (mult < 0 ? -1 : 1);
   3431 	    ctx->text.mult = (short)(ctx->text.mult * 10 + (params[0][0] - '0') *
   3432 			     (mult < 0 ? -1 : 1));
   3433 	}
   3434 	if (mult != ctx->text.mult || mult >= 32767) {	/* checks for overflow */
   3435 	    XBell(XtDisplay(w), 0);
   3436 	    ctx->text.mult = 1;
   3437 	    ctx->text.numeric = False;
   3438 	    return;
   3439 	}
   3440     }
   3441     else
   3442 	InsertChar(w, event, params, num_params);
   3443 }
   3444 
   3445 /*ARGSUSED*/
   3446 static void
   3447 KeyboardReset(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   3448 {
   3449     TextWidget ctx = (TextWidget)w;
   3450 
   3451     ctx->text.numeric = False;
   3452     ctx->text.mult = 1;
   3453 
   3454     (void)_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
   3455 
   3456     if (ctx->text.kill_ring_ptr) {
   3457 	--ctx->text.kill_ring_ptr->refcount;
   3458 	ctx->text.kill_ring_ptr = NULL;
   3459     }
   3460     ctx->text.kill_ring = 0;
   3461 
   3462     XBell(XtDisplay(w), 0);
   3463 }
   3464 #endif /* OLDXAW */
   3465 
   3466 /* Multiply() - action
   3467  *
   3468  * The parameter list may contain either a number or the string 'Reset'.
   3469  *
   3470  * A number will multiply the current multiplication factor by that number.
   3471  * Many of the text widget actions will will perform n actions, where n is
   3472  * the multiplication factor.
   3473  *
   3474  * The string reset will reset the mutiplication factor to 1. */
   3475 /*ARGSUSED*/
   3476 static void
   3477 Multiply(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
   3478 {
   3479     TextWidget ctx = (TextWidget)w;
   3480     int mult;
   3481 
   3482     if (*num_params != 1) {
   3483 	XtAppError(XtWidgetToApplicationContext(w),
   3484 		   "Xaw Text Widget: multiply() takes exactly one argument.");
   3485 	XBell(XtDisplay(w), 0);
   3486 	return;
   3487     }
   3488 
   3489     if ((params[0][0] == 'r') || (params[0][0] == 'R')) {
   3490 	XBell(XtDisplay(w), 0);
   3491 #ifndef OLDXAW
   3492 	ctx->text.numeric = False;
   3493 #endif
   3494 	ctx->text.mult = 1;
   3495 	return;
   3496     }
   3497 
   3498 #ifndef OLDXAW
   3499     if (params[0][0] == 's' || params[0][0] == 'S') {
   3500 	ctx->text.numeric = True;
   3501 	ctx->text.mult = 0;
   3502 	return;
   3503     }
   3504     else
   3505 #endif
   3506 	if ((mult = atoi(params[0])) == 0) {
   3507 	char buf[BUFSIZ];
   3508 
   3509 	snprintf(buf, sizeof(buf),
   3510 		 "Xaw Text Widget: multiply() argument "
   3511 		 "must be a number greater than zero, or 'Reset'.");
   3512 	XtAppError(XtWidgetToApplicationContext(w), buf);
   3513 	XBell(XtDisplay(w), 50);
   3514 	return;
   3515     }
   3516 
   3517     ctx->text.mult = (short)(ctx->text.mult * mult);
   3518 }
   3519 
   3520 /* StripOutOldCRs() - called from FormRegion
   3521  *
   3522  * removes CRs in widget ctx, from from to to.
   3523  *
   3524  * RETURNS: the new ending location (we may add some characters),
   3525  * or XawReplaceError if the widget can't be written to. */
   3526 static XawTextPosition
   3527 StripOutOldCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
   3528 	       XawTextPosition *pos, int num_pos)
   3529 {
   3530     XawTextPosition startPos, endPos, eop_begin, eop_end;
   3531     Widget src = ctx->text.source;
   3532     XawTextBlock text;
   3533     char *buf;
   3534     int idx;
   3535 
   3536     /* Initialize our TextBlock with two spaces. */
   3537     text.firstPos = 0;
   3538     text.format = (unsigned long)_XawTextFormat(ctx);
   3539     if (text.format == XawFmt8Bit) {
   3540         text.ptr= (char*)" ";
   3541     } else {
   3542 	static wchar_t wc_two_spaces[3];
   3543 
   3544 	wc_two_spaces[0] = _Xaw_atowc(XawSP);
   3545 	wc_two_spaces[1] = _Xaw_atowc(XawSP);
   3546 	wc_two_spaces[2] = 0;
   3547 	text.ptr = (char*)wc_two_spaces;
   3548     }
   3549 
   3550     /* Strip out CR's. */
   3551     eop_begin = eop_end = startPos = from;
   3552 
   3553     /* CONSTCOND */
   3554     while (TRUE) {
   3555 	XawTextPosition temp;
   3556 
   3557 	endPos = SrcScan(src, startPos, XawstEOL, XawsdRight, 1, False);
   3558 
   3559 	temp = SrcScan(src, endPos, XawstWhiteSpace, XawsdLeft, 1, False);
   3560 	temp = SrcScan(src, temp,   XawstWhiteSpace, XawsdRight,1, False);
   3561 
   3562 	if (temp > startPos)
   3563 	    endPos = temp;
   3564 
   3565 	if (endPos >= to)
   3566 	    break;
   3567 
   3568 	if (endPos >= eop_begin) {
   3569 	    startPos = eop_end;
   3570 	    eop_begin=SrcScan(src, startPos, XawstParagraph,
   3571 			      XawsdRight, 1,False);
   3572 	    eop_end = SrcScan(src, startPos, XawstParagraph,
   3573 			      XawsdRight, 1, True);
   3574 	}
   3575 	else {
   3576 	    XawTextPosition periodPos, next_word;
   3577 	    int i, len;
   3578 
   3579 	    periodPos = SrcScan(src, endPos, XawstPositions,
   3580 				XawsdLeft, 1, True);
   3581 	    next_word = SrcScan(src, endPos, XawstWhiteSpace,
   3582 				XawsdRight, 1, False);
   3583 
   3584 	    len = (int)(next_word - periodPos);
   3585 
   3586 	    text.length = 1;
   3587 	    buf = _XawTextGetText(ctx, periodPos, next_word);
   3588 	    if (text.format == XawFmtWide) {
   3589 		if (periodPos < endPos && ((wchar_t*)buf)[0] == _Xaw_atowc('.'))
   3590 		  text.length++;
   3591 	    }
   3592 	    else
   3593 		if (periodPos < endPos && buf[0] == '.')
   3594 		    text.length++;	  /* Put in two spaces. */
   3595 
   3596 	    /*
   3597 	     * Remove all extra spaces.
   3598 	     */
   3599 	    for (i = 1 ; i < len; i++)
   3600 		if (text.format ==  XawFmtWide) {
   3601 		    if (!iswspace(((wchar_t*)buf)[i]) || ((periodPos + i) >= to))
   3602 			break;
   3603 		}
   3604 		else if (!isspace((unsigned char)buf[i]) || (periodPos + i) >= to)
   3605 		    break;
   3606 
   3607 	    XtFree(buf);
   3608 
   3609 	    to -= (i - text.length - 1);
   3610 	    startPos = SrcScan(src, periodPos, XawstPositions,
   3611 			       XawsdRight, i, True);
   3612 	    if (_XawTextReplace(ctx, endPos, startPos, &text) != XawEditDone)
   3613 		return (XawReplaceError);
   3614 
   3615 	    for (idx = 0; idx < num_pos; idx++) {
   3616 		if (endPos < pos[idx]) {
   3617 		    if (startPos < pos[idx])
   3618 			pos[idx] -= startPos - endPos;
   3619 		    else
   3620 			pos[idx] = endPos;
   3621 		    pos[idx] += text.length;
   3622 		}
   3623 	    }
   3624 
   3625 	    startPos -= i - text.length;
   3626 	}
   3627     }
   3628 
   3629     return (to);
   3630 }
   3631 
   3632 /* InsertNewCRs() - called from FormRegion
   3633  *
   3634  * inserts new CRs for FormRegion, thus for FormParagraph action */
   3635 static void
   3636 InsertNewCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
   3637 	     XawTextPosition *pos, int num_pos)
   3638 {
   3639     XawTextPosition startPos;
   3640     XawTextBlock text;
   3641     int i, width, height, wwidth, idx;
   3642 
   3643     text.firstPos = 0;
   3644     text.length = 1;
   3645     text.format = (unsigned long)_XawTextFormat(ctx);
   3646 
   3647     if (text.format == XawFmt8Bit) {
   3648 	text.ptr = (char*)"\n";
   3649     } else {
   3650 	static wchar_t wide_CR[2];
   3651 
   3652 	wide_CR[0] = _Xaw_atowc(XawLF);
   3653 	wide_CR[1] = 0;
   3654 	text.ptr = (char*)wide_CR;
   3655     }
   3656 
   3657     startPos = from;
   3658 
   3659     wwidth = (int)XtWidth(ctx) - (int)HMargins(ctx);
   3660     if (ctx->text.wrap != XawtextWrapNever) {
   3661 	XRectangle cursor;
   3662 
   3663 	XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
   3664 	wwidth -= (int)cursor.width;
   3665     }
   3666     wwidth = XawMax(0, wwidth);
   3667 
   3668     /* CONSTCOND */
   3669     while (TRUE) {
   3670 	int len;
   3671 	char *buf;
   3672 	XawTextPosition endPos, space, eol;
   3673 
   3674 	XawTextSinkFindPosition(ctx->text.sink, startPos,
   3675 				(int)ctx->text.r_margin.left, wwidth,
   3676 				True, &eol, &width, &height);
   3677 	if (eol == startPos)
   3678 	    ++eol;
   3679 	if (eol >= to)
   3680 	    break;
   3681 
   3682 	eol = SrcScan(ctx->text.source, eol, XawstPositions,
   3683 		      XawsdLeft, 1, True);
   3684 	space = SrcScan(ctx->text.source, eol, XawstWhiteSpace,
   3685 			XawsdRight,1, True);
   3686 
   3687 	startPos = endPos = eol;
   3688 	if (eol == space)
   3689 	    return;
   3690 
   3691 	len = (int)(space - eol);
   3692 	buf = _XawTextGetText(ctx, eol, space);
   3693 	for (i = 0 ; i < len ; i++)
   3694 	    if (text.format == XawFmtWide) {
   3695 		if (!iswspace(((wchar_t*)buf)[i]))
   3696 		    break;
   3697 	    }
   3698 	    else if (!isspace((unsigned char)buf[i]))
   3699 		break;
   3700 
   3701 	to -= (i - 1);
   3702 	endPos = SrcScan(ctx->text.source, endPos,
   3703 			 XawstPositions, XawsdRight, i, True);
   3704 	XtFree(buf);
   3705 
   3706 	if (_XawTextReplace(ctx, startPos, endPos, &text))
   3707 	    return;
   3708 
   3709 	for (idx = 0; idx < num_pos; idx++) {
   3710 	    if (startPos < pos[idx]) {
   3711 		if (endPos < pos[idx])
   3712 		    pos[idx] -= endPos - startPos;
   3713 		else
   3714 		    pos[idx] = startPos;
   3715 		pos[idx] += text.length;
   3716 	    }
   3717 	}
   3718 
   3719 	startPos = SrcScan(ctx->text.source, startPos,
   3720 			   XawstPositions, XawsdRight, 1, True);
   3721     }
   3722 }
   3723 
   3724 /* FormRegion() - called by FormParagraph
   3725  *
   3726  * oversees the work of paragraph-forming a region
   3727  *
   3728  * Return:
   3729  *	XawEditDone if successful, or XawReplaceError
   3730  */
   3731 static int
   3732 FormRegion(TextWidget ctx, XawTextPosition from, XawTextPosition to,
   3733 	   XawTextPosition *pos, int num_pos)
   3734 {
   3735 #ifndef OLDXAW
   3736     Bool format = ctx->text.auto_fill
   3737 	&& ctx->text.left_column < ctx->text.right_column;
   3738 #endif
   3739 
   3740     if (from >= to)
   3741 	return (XawEditDone);
   3742 
   3743 #ifndef OLDXAW
   3744     if (format) {
   3745 	XawTextPosition len = ctx->text.lastPos;
   3746 	int inc = 0;
   3747 
   3748 	if (ctx->text.justify == XawjustifyLeft ||
   3749 	    ctx->text.justify == XawjustifyFull) {
   3750 	    Untabify(ctx, from, to, pos, num_pos, NULL);
   3751 	    to += ctx->text.lastPos - len;
   3752 	    (void)BlankLine((Widget)ctx, from, &inc);
   3753 	    if (from + inc >= to)
   3754 		return (XawEditDone);
   3755 	}
   3756 	if (!StripSpaces(ctx, from + inc, to, pos, num_pos, NULL))
   3757 	    return (XawReplaceError);
   3758 
   3759 	FormatText(ctx, from, ctx->text.justify != XawjustifyFull, pos, num_pos);
   3760     }
   3761     else {
   3762 #endif
   3763 	if ((to = StripOutOldCRs(ctx, from, to, pos, num_pos)) == XawReplaceError)
   3764 	    return (XawReplaceError);
   3765 	InsertNewCRs(ctx, from, to, pos, num_pos);
   3766 #ifndef OLDXAW
   3767     }
   3768 #endif
   3769     ctx->text.from_left = -1;
   3770 
   3771     return (XawEditDone);
   3772 }
   3773 
   3774 #ifndef OLDXAW
   3775 static Bool
   3776 BlankLine(Widget w, XawTextPosition pos, int *blanks_return)
   3777 {
   3778     int i, blanks = 0;
   3779     XawTextBlock block;
   3780     Widget src = XawTextGetSource(w);
   3781     XawTextPosition l = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
   3782     XawTextPosition r = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
   3783 
   3784     while (l < r) {
   3785 	l = XawTextSourceRead(src, l, &block, (int)(r - l));
   3786 	if (block.length == 0) {
   3787 	    if (blanks_return)
   3788 		*blanks_return = blanks;
   3789 	    return (True);
   3790 	}
   3791 	if (XawTextFormat((TextWidget)w, XawFmt8Bit)) {
   3792 	    for (i = 0; i < block.length; i++, blanks++)
   3793 		if (block.ptr[i] != ' ' &&
   3794 		    block.ptr[i] != '\t') {
   3795 		    if (blanks_return)
   3796 			*blanks_return = blanks;
   3797 		    return (block.ptr[i] == '\n');
   3798 		}
   3799 	}
   3800 	else if (XawTextFormat((TextWidget)w, XawFmtWide)) {
   3801 	    for (i = 0; i < block.length; i++, blanks++)
   3802 		if (_Xaw_atowc(XawSP) != ((wchar_t*)block.ptr)[i] &&
   3803 		    _Xaw_atowc(XawTAB) != ((wchar_t*)block.ptr)[i]) {
   3804 		    if (blanks_return)
   3805 			*blanks_return = blanks;
   3806 		    return (_Xaw_atowc(XawLF) == ((wchar_t*)block.ptr)[i]);
   3807 		}
   3808 	}
   3809     }
   3810 
   3811     return (True);
   3812 }
   3813 
   3814 static Bool
   3815 GetBlockBoundaries(TextWidget ctx,
   3816 		   XawTextPosition *from_return, XawTextPosition *to_return)
   3817 {
   3818     XawTextPosition from, to;
   3819 
   3820     if (ctx->text.auto_fill && ctx->text.left_column < ctx->text.right_column) {
   3821 	if (ctx->text.s.left != ctx->text.s.right) {
   3822 	    from = SrcScan(ctx->text.source,
   3823 			   XawMin(ctx->text.s.left, ctx->text.s.right),
   3824 			   XawstEOL, XawsdLeft, 1, False);
   3825 	    to   = SrcScan(ctx->text.source,
   3826 			   XawMax(ctx->text.s.left, ctx->text.s.right),
   3827 			   XawstEOL, XawsdRight, 1, False);
   3828 	}
   3829 	else {
   3830 	    XawTextBlock block;
   3831 	    XawTextPosition tmp;
   3832 	    Bool first;
   3833 
   3834 	    from = to = ctx->text.insertPos;
   3835 
   3836 	    /* find from position */
   3837 	    first = True;
   3838 	    while (1) {
   3839 		tmp = from;
   3840 		from = SrcScan(ctx->text.source, from, XawstEOL, XawsdLeft,
   3841 			       1 + !first, False);
   3842 		XawTextSourceRead(ctx->text.source, from, &block, 1);
   3843 		if (block.length == 0 ||
   3844 		    (XawTextFormat(ctx, XawFmt8Bit) &&
   3845 		     block.ptr[0] != ' ' &&
   3846 		     block.ptr[0] != '\t' &&
   3847 		     !isalnum(*(unsigned char*)block.ptr)) ||
   3848 		    (XawTextFormat(ctx, XawFmtWide) &&
   3849 		     _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
   3850 		     _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
   3851 		     !iswalnum((wint_t)*(wchar_t*)block.ptr)) ||
   3852 		    BlankLine((Widget)ctx, from, NULL)) {
   3853 		    from = tmp;
   3854 		    break;
   3855 		}
   3856 		if (from == tmp && !first)
   3857 		    break;
   3858 		first = False;
   3859 	    }
   3860 	    if (first)
   3861 		return (False);
   3862 
   3863 	    /* find to position */
   3864 	    first = True;
   3865 	    while (1) {
   3866 		tmp = to;
   3867 		to = SrcScan(ctx->text.source, to, XawstEOL, XawsdRight,
   3868 			     1 + !first, False);
   3869 		XawTextSourceRead(ctx->text.source, to + (to < ctx->text.lastPos),
   3870 				  &block, 1);
   3871 		if (block.length == 0 ||
   3872 		    (XawTextFormat(ctx, XawFmt8Bit) &&
   3873 		     block.ptr[0] != ' ' &&
   3874 		     block.ptr[0] != '\t' &&
   3875 		     !isalnum(*(unsigned char*)block.ptr)) ||
   3876 		    (XawTextFormat(ctx, XawFmtWide) &&
   3877 		     _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
   3878 		     _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
   3879 		     !iswalnum((wint_t)*(wchar_t*)block.ptr)) ||
   3880 		    BlankLine((Widget)ctx, to, NULL))
   3881 		    break;
   3882 		if (to == tmp && !first)
   3883 		    break;
   3884 		first = False;
   3885 	    }
   3886 	}
   3887     }
   3888     else {
   3889 	from = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
   3890 		       XawsdLeft, 1, False);
   3891 	if (BlankLine((Widget)ctx, from, NULL))
   3892 	    return (False);
   3893 	from = SrcScan(ctx->text.source, from, XawstParagraph,
   3894 		       XawsdLeft, 1, False);
   3895 	if (BlankLine((Widget)ctx, from, NULL))
   3896 	    from = SrcScan(ctx->text.source, from, XawstEOL,
   3897 			   XawsdRight, 1, True);
   3898 	to = SrcScan(ctx->text.source, from, XawstParagraph,
   3899 			XawsdRight, 1, False);
   3900     }
   3901 
   3902     if (from < to) {
   3903 	*from_return = from;
   3904 	*to_return = to;
   3905 	return (True);
   3906     }
   3907 
   3908     return (False);
   3909 }
   3910 #endif /* OLDXAW */
   3911 
   3912 /* FormParagraph() - action
   3913  *
   3914  * removes and reinserts CRs to maximize line length without clipping */
   3915 /*ARGSUSED*/
   3916 static void
   3917 FormParagraph(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   3918 {
   3919     TextWidget ctx = (TextWidget)w;
   3920     XawTextPosition from, to, buf[32], *pos;
   3921 #ifndef OLDXAW
   3922     XawTextPosition endPos = 0;
   3923     char *lbuf = NULL, *rbuf;
   3924     TextSrcObject src = (TextSrcObject)ctx->text.source;
   3925     Cardinal i;
   3926     Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
   3927 #endif
   3928 
   3929     StartAction(ctx, event);
   3930 
   3931 #ifndef OLDXAW
   3932     pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, buf);
   3933     for (i = 0; i < src->textSrc.num_text; i++)
   3934 	pos[i] = ((TextWidget)src->textSrc.text[i])->text.old_insert;
   3935 #else
   3936     pos = buf;
   3937     *pos = ctx->text.old_insert;
   3938 #endif
   3939 
   3940 #ifndef OLDXAW
   3941     if (!GetBlockBoundaries(ctx, &from, &to)) {
   3942 	EndAction(ctx);
   3943 	XawStackFree(pos, buf);
   3944 	return;
   3945     }
   3946 
   3947     if (undo) {
   3948 	src->textSrc.undo_state = True;
   3949 	lbuf = _XawTextGetText(ctx, from, to);
   3950 	endPos = ctx->text.lastPos;
   3951     }
   3952 
   3953     if (FormRegion(ctx, from, to, pos, (int)src->textSrc.num_text) == XawReplaceError) {
   3954 	XawStackFree(pos, buf);
   3955 	pos = buf;
   3956 #else
   3957     from =  SrcScan(ctx->text.source, ctx->text.insertPos,
   3958 		    XawstParagraph, XawsdLeft, 1, False);
   3959     to  =   SrcScan(ctx->text.source, from,
   3960 		    XawstParagraph, XawsdRight, 1, False);
   3961 
   3962     if (FormRegion(ctx, from, to, pos, 1) == XawReplaceError) {
   3963 #endif
   3964 	XBell(XtDisplay(w), 0);
   3965 #ifndef OLDXAW
   3966 	if (undo) {
   3967 	    src->textSrc.undo_state = False;
   3968 	    XtFree(lbuf);
   3969 	}
   3970 #endif
   3971     }
   3972 #ifndef OLDXAW
   3973     else if (undo) {
   3974 	/* makes the form-paragraph only one undo/redo step */
   3975 	unsigned llen, rlen, size;
   3976 	XawTextBlock block;
   3977 
   3978 	llen = (unsigned)(to - from);
   3979 	rlen = (unsigned)(llen + (ctx->text.lastPos - endPos));
   3980 
   3981 	block.firstPos = 0;
   3982 	block.format = (unsigned long)_XawTextFormat(ctx);
   3983 
   3984 	rbuf = _XawTextGetText(ctx, from, from + rlen);
   3985 
   3986 	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
   3987 	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
   3988 	    block.ptr = lbuf;
   3989 	    block.length = (int)llen;
   3990 	    _XawTextReplace(ctx, from, from + rlen, &block);
   3991 
   3992 	    src->textSrc.undo_state = False;
   3993 	    block.ptr = rbuf;
   3994 	    block.length = (int)rlen;
   3995 	    _XawTextReplace(ctx, from, from + llen, &block);
   3996 	}
   3997 	else
   3998 	    src->textSrc.undo_state = False;
   3999 	XtFree(lbuf);
   4000 	XtFree(rbuf);
   4001     }
   4002 
   4003     for (i = 0; i < src->textSrc.num_text; i++) {
   4004 	TextWidget tw = (TextWidget)src->textSrc.text[i];
   4005 
   4006 	tw->text.old_insert = tw->text.insertPos = pos[i];
   4007 	_XawTextBuildLineTable(tw, SrcScan((Widget)src, tw->text.lt.top, XawstEOL,
   4008 			       XawsdLeft, 1, False), False);
   4009 	tw->text.clear_to_eol = True;
   4010     }
   4011     XawStackFree(pos, buf);
   4012 #else
   4013     ctx->text.old_insert = ctx->text.insertPos = *pos;
   4014     _XawTextBuildLineTable(ctx, SrcScan(ctx->text.source, ctx->text.lt.top,
   4015 			   XawstEOL, XawsdLeft, 1, False), False);
   4016     ctx->text.clear_to_eol = True;
   4017 #endif
   4018     ctx->text.showposition = True;
   4019 
   4020     EndAction(ctx);
   4021 }
   4022 
   4023 /* TransposeCharacters() - action
   4024  *
   4025  * Swaps the character to the left of the mark
   4026  * with the character to the right of the mark */
   4027 /*ARGSUSED*/
   4028 static void
   4029 TransposeCharacters(Widget w, XEvent *event,
   4030 		    String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   4031 {
   4032     TextWidget ctx = (TextWidget)w;
   4033     XawTextPosition start, end;
   4034     XawTextBlock text;
   4035     char *buf;
   4036     int i, mult = MULT(ctx);
   4037 
   4038     if (mult < 0) {
   4039 	ctx->text.mult = 1;
   4040 	return;
   4041     }
   4042 
   4043     StartAction(ctx, event);
   4044 
   4045     /* Get bounds. */
   4046 
   4047     start = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
   4048 		    XawsdLeft, 1, True);
   4049     end = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
   4050 		  XawsdRight, mult, True);
   4051 
   4052     /* Make sure we aren't at the very beginning or end of the buffer. */
   4053 
   4054     if (start == ctx->text.insertPos || end == ctx->text.insertPos) {
   4055 	XBell(XtDisplay(w), 0);   /* complain. */
   4056 	EndAction(ctx);
   4057 	return;
   4058     }
   4059 
   4060     ctx->text.from_left = -1;
   4061     ctx->text.insertPos = end;
   4062 
   4063     text.firstPos = 0;
   4064     text.format = (unsigned long)_XawTextFormat(ctx);
   4065 
   4066     /* Retrieve text and swap the characters. */
   4067     if (text.format == XawFmtWide) {
   4068 	wchar_t wc;
   4069 	wchar_t *wbuf;
   4070 
   4071 	wbuf = (wchar_t*)_XawTextGetText(ctx, start, end);
   4072 	text.length = (int)wcslen(wbuf);
   4073 	wc = wbuf[0];
   4074 	for (i = 1; i < text.length; i++)
   4075 	    wbuf[i - 1] = wbuf[i];
   4076 	wbuf[i - 1] = wc;
   4077 	buf = (char*)wbuf; /* so that it gets assigned and freed */
   4078     }
   4079     else {	/* thus text.format == XawFmt8Bit */
   4080 	char c;
   4081 
   4082 	buf = _XawTextGetText(ctx, start, end);
   4083 	text.length = (int)strlen(buf);
   4084 	c = buf[0];
   4085 	for (i = 1; i < text.length; i++)
   4086 	    buf[i - 1] = buf[i];
   4087 	buf[i - 1] = c;
   4088     }
   4089 
   4090     text.ptr = buf;
   4091 
   4092     /* Store new text in source. */
   4093 
   4094     if (_XawTextReplace (ctx, start, end, &text))
   4095 	XBell(XtDisplay(w), 0);
   4096     XtFree((char *)buf);
   4097     EndAction(ctx);
   4098 }
   4099 
   4100 #ifndef OLDXAW
   4101 /*ARGSUSED*/
   4102 static void
   4103 Undo(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   4104 {
   4105     TextWidget ctx = (TextWidget)w;
   4106     int mul = MULT(ctx);
   4107     Bool toggle = False;
   4108 
   4109     if (mul < 0) {
   4110 	toggle = True;
   4111 	_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
   4112 	ctx->text.mult = (short)(mul = -mul);
   4113     }
   4114 
   4115     StartAction(ctx, event);
   4116     for (; mul; --mul)
   4117 	if (!_XawTextSrcUndo((TextSrcObject)ctx->text.source, &ctx->text.insertPos))
   4118 	    break;
   4119     ctx->text.showposition = True;
   4120 
   4121     if (toggle)
   4122 	_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
   4123     EndAction(ctx);
   4124 }
   4125 #endif
   4126 
   4127 /* NoOp() - action
   4128  * This action performs no action, and allows the user or
   4129  * application programmer to unbind a translation.
   4130  *
   4131  * Note: If the parameter list contains the string "RingBell" then
   4132  *	 this action will ring the bell.
   4133  */
   4134 /*ARGSUSED*/
   4135 static void
   4136 NoOp(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
   4137 {
   4138     if (*num_params != 1)
   4139 	return;
   4140 
   4141     switch(params[0][0]) {
   4142 	case 'R':
   4143 	case 'r':
   4144 	    XBell(XtDisplay(w), 0);
   4145 	    /*FALLTHROUGH*/
   4146 	default:
   4147 	    break;
   4148     }
   4149 }
   4150 
   4151 /* Reconnect() - action
   4152  * This reconnects to the input method.  The user will typically call
   4153  * this action if/when connection has been severed, or when the app
   4154  * was started up before an IM was started up
   4155  */
   4156 /*ARGSUSED*/
   4157 static void
   4158 Reconnect(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   4159 {
   4160     _XawImReconnect(w);
   4161 }
   4162 
   4163 #define	CAPITALIZE	1
   4164 #define	DOWNCASE	2
   4165 #define UPCASE		3
   4166 
   4167 #ifdef NO_LIBC_I18N
   4168 static int
   4169 ToLower(int ch)
   4170 {
   4171     char buf[2];
   4172 
   4173     *buf = ch;
   4174     XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
   4175 
   4176     return (*buf);
   4177 }
   4178 
   4179 static int
   4180 ToUpper(int ch)
   4181 {
   4182     char buf[2];
   4183 
   4184     *buf = ch;
   4185     XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
   4186 
   4187     return (*buf);
   4188 }
   4189 
   4190 static int
   4191 IsAlnum(int ch)
   4192 {
   4193     return ((ch >= '0' && ch <= '9') || ToUpper(ch) != ch || ToLower(ch) != ch);
   4194 }
   4195 
   4196 static int
   4197 IsLower(int ch)
   4198 {
   4199     char upbuf[2];
   4200     char lobuf[2];
   4201 
   4202     *upbuf = *lobuf = ch;
   4203     XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
   4204     XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
   4205 
   4206     return (*lobuf != *upbuf && ch == *lobuf);
   4207 }
   4208 
   4209 static int
   4210 IsUpper(int ch)
   4211 {
   4212     char upbuf[2];
   4213     char lobuf[2];
   4214 
   4215     *upbuf = *lobuf = ch;
   4216     XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
   4217     XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
   4218 
   4219     return (*lobuf != *upbuf && ch == *upbuf);
   4220 }
   4221 #else
   4222 #define	ToLower	tolower
   4223 #define ToUpper	toupper
   4224 #define IsAlnum isalnum
   4225 #define IsLower islower
   4226 #define IsUpper isupper
   4227 #endif
   4228 
   4229 static void
   4230 CaseProc(Widget w, XEvent *event, int cmd)
   4231 {
   4232     TextWidget ctx = (TextWidget)w;
   4233     short mul = MULT(ctx);
   4234     XawTextPosition left, right;
   4235     XawTextBlock block;
   4236     Bool changed = False;
   4237     unsigned char ch, mb[sizeof(wchar_t)];
   4238     int i, count;
   4239 
   4240     if (mul > 0)
   4241 	right = SrcScan(ctx->text.source, left = ctx->text.insertPos,
   4242 			XawstAlphaNumeric, XawsdRight, mul, False);
   4243     else
   4244 	left = SrcScan(ctx->text.source, right = ctx->text.insertPos,
   4245 		       XawstAlphaNumeric, XawsdLeft, 1 + -mul, False);
   4246     block.firstPos = 0;
   4247     block.format = (unsigned long)_XawTextFormat(ctx);
   4248     block.length = (int)(right - left);
   4249     block.ptr = _XawTextGetText(ctx, left, right);
   4250 
   4251     count = 0;
   4252     if (block.format == XawFmt8Bit)
   4253 	for (i = 0; i < block.length; i++) {
   4254 	    if (!IsAlnum(*mb = (unsigned char)block.ptr[i]))
   4255 		count = 0;
   4256 	    else if (++count == 1 || cmd != CAPITALIZE) {
   4257 		ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb));
   4258 		if (ch != *mb) {
   4259 		    changed = True;
   4260 		    block.ptr[i] = (char)ch;
   4261 		}
   4262 	    }
   4263 	    else if (cmd == CAPITALIZE) {
   4264 		if ((ch = (unsigned char)(ToLower(*mb))) != *mb) {
   4265 		    changed = True;
   4266 		    block.ptr[i] = (char)ch;
   4267 		}
   4268 	    }
   4269 	}
   4270     else
   4271 	for (i = 0; i < block.length; i++) {
   4272 	    wctomb((char*)mb, ((wchar_t*)block.ptr)[i]);
   4273 	    if (!IsAlnum(*mb))
   4274 		count = 0;
   4275 	    else if (++count == 1 || cmd != CAPITALIZE) {
   4276 		ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb));
   4277 		if (ch != *mb) {
   4278 		    changed = True;
   4279 		    ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
   4280 		}
   4281 	    }
   4282 	    else if (cmd == CAPITALIZE) {
   4283 		if ((ch = (unsigned char)(ToLower(*mb))) != *mb) {
   4284 		    changed = True;
   4285 		    ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
   4286 		}
   4287 	    }
   4288 	}
   4289 
   4290     StartAction(ctx, event);
   4291     if (changed && _XawTextReplace(ctx, left, right, &block) != XawEditDone)
   4292 	XBell(XtDisplay(ctx), 0);
   4293     ctx->text.insertPos = right;
   4294     EndAction(ctx);
   4295 
   4296     XtFree(block.ptr);
   4297 }
   4298 
   4299 /*ARGSUSED*/
   4300 static void
   4301 CapitalizeWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   4302 {
   4303     CaseProc(w, event, CAPITALIZE);
   4304 }
   4305 
   4306 /*ARGSUSED*/
   4307 static void
   4308 DowncaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   4309 {
   4310     CaseProc(w, event, DOWNCASE);
   4311 }
   4312 
   4313 /*ARGSUSED*/
   4314 static void
   4315 UpcaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
   4316 {
   4317     CaseProc(w, event, UPCASE);
   4318 }
   4319 #undef CAPITALIZE
   4320 #undef DOWNCASE
   4321 #undef UPCASE
   4322 
   4323 XtActionsRec _XawTextActionsTable[] = {
   4324   /* motion */
   4325   {"forward-character",		MoveForwardChar},
   4326   {"backward-character",	MoveBackwardChar},
   4327   {"forward-word",		MoveForwardWord},
   4328   {"backward-word",		MoveBackwardWord},
   4329   {"forward-paragraph",		MoveForwardParagraph},
   4330   {"backward-paragraph",	MoveBackwardParagraph},
   4331   {"beginning-of-line",		MoveToLineStart},
   4332   {"end-of-line",		MoveToLineEnd},
   4333   {"next-line",			MoveNextLine},
   4334   {"previous-line",		MovePreviousLine},
   4335   {"next-page",			MoveNextPage},
   4336   {"previous-page",		MovePreviousPage},
   4337   {"beginning-of-file",		MoveBeginningOfFile},
   4338   {"end-of-file",		MoveEndOfFile},
   4339   {"scroll-one-line-up",	ScrollOneLineUp},
   4340   {"scroll-one-line-down",	ScrollOneLineDown},
   4341 
   4342   /* delete */
   4343   {"delete-next-character",	DeleteForwardChar},
   4344   {"delete-previous-character",	DeleteBackwardChar},
   4345   {"delete-next-word",		DeleteForwardWord},
   4346   {"delete-previous-word",	DeleteBackwardWord},
   4347   {"delete-selection",		DeleteCurrentSelection},
   4348   {"delete",			Delete},
   4349 
   4350   /* kill */
   4351   {"kill-word",			KillForwardWord},
   4352   {"backward-kill-word",	KillBackwardWord},
   4353   {"kill-selection",		KillCurrentSelection},
   4354   {"kill-to-end-of-line",	KillToEndOfLine},
   4355   {"kill-to-end-of-paragraph",	KillToEndOfParagraph},
   4356 
   4357   /* new line */
   4358   {"newline-and-indent",	InsertNewLineAndIndent},
   4359   {"newline-and-backup",	InsertNewLineAndBackup},
   4360   {"newline",			InsertNewLine},
   4361 
   4362   /* selection */
   4363   {"select-word",		SelectWord},
   4364   {"select-all",		SelectAll},
   4365   {"select-start",		SelectStart},
   4366   {"select-adjust",		SelectAdjust},
   4367   {"select-end",		SelectEnd},
   4368   {"select-save",		SelectSave},
   4369   {"extend-start",		ExtendStart},
   4370   {"extend-adjust",		ExtendAdjust},
   4371   {"extend-end", 		ExtendEnd},
   4372   {"insert-selection",		InsertSelection},
   4373 
   4374   /* miscellaneous */
   4375   {"redraw-display",		RedrawDisplay},
   4376   {"insert-file",		_XawTextInsertFile},
   4377   {"search",			_XawTextSearch},
   4378   {"insert-char",		InsertChar},
   4379   {"insert-string",		InsertString},
   4380   {"focus-in",			TextFocusIn},
   4381   {"focus-out",			TextFocusOut},
   4382   {"enter-window",		TextEnterWindow},
   4383   {"leave-window",		TextLeaveWindow},
   4384   {"display-caret",		DisplayCaret},
   4385   {"multiply",			Multiply},
   4386   {"form-paragraph",		FormParagraph},
   4387   {"transpose-characters",	TransposeCharacters},
   4388   {"set-keyboard-focus",	SetKeyboardFocus},
   4389 #ifndef OLDXAW
   4390   {"numeric",			Numeric},
   4391   {"undo",			Undo},
   4392   {"keyboard-reset",		KeyboardReset},
   4393   {"kill-ring-yank",		KillRingYank},
   4394   {"toggle-overwrite",		ToggleOverwrite},
   4395   {"indent",			Indent},
   4396 #endif
   4397   {"no-op",			NoOp},
   4398 
   4399   /* case transformations */
   4400   {"capitalize-word",		CapitalizeWord},
   4401   {"downcase-word",		DowncaseWord},
   4402   {"upcase-word",		UpcaseWord},
   4403 
   4404   /* action to bind translations for text dialogs */
   4405   {"InsertFileAction",		_XawTextInsertFileAction},
   4406   {"DoSearchAction",		_XawTextDoSearchAction},
   4407   {"DoReplaceAction",		_XawTextDoReplaceAction},
   4408   {"SetField",			_XawTextSetField},
   4409   {"PopdownSearchAction",	_XawTextPopdownSearchAction},
   4410 
   4411   /* reconnect to Input Method */
   4412   {"reconnect-im",		Reconnect} /* Li Yuhong, Omron KK, 1991 */
   4413 };
   4414 
   4415 Cardinal _XawTextActionsTableCount = XtNumber(_XawTextActionsTable);
   4416