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(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
ParameterError(Widget w,String param)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
StartAction(TextWidget ctx,XEvent * event)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
NotePosition(TextWidget ctx,XEvent * event)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
EndAction(TextWidget ctx)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
_SelectionReceived(Widget w,XtPointer client_data,Atom * selection _X_UNUSED,Atom * type,XtPointer value,unsigned long * length,int * format _X_UNUSED)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 	XTextProperty textprop;
407 	wchar_t **wlist;
408 	int count;
409 
410 	textprop.encoding = *type;
411 	textprop.value = (unsigned char *)value;
412 	textprop.nitems = strlen(value);
413 	textprop.format = 8;
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 = (const 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
GetSelection(Widget w,Time timev,String * params,Cardinal num_params)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
InsertSelection(Widget w,XEvent * event,String * params,Cardinal * num_params)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
Move(TextWidget ctx,XEvent * event,XawTextScanDirection dir,XawTextScanType type,Bool include)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
MoveForwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
MoveBackwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
MoveForwardWord(Widget w,XEvent * event,String * p,Cardinal * n)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
MoveBackwardWord(Widget w,XEvent * event,String * p,Cardinal * n)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
MoveForwardParagraph(Widget w,XEvent * event,String * p,Cardinal * n)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
MoveBackwardParagraph(Widget w,XEvent * event,String * p,Cardinal * n)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
MoveToLineEnd(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
MoveToLineStart(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
MoveLine(TextWidget ctx,XEvent * event,XawTextScanDirection dir)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
MoveNextLine(Widget w,XEvent * event,String * p,Cardinal * n)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
MovePreviousLine(Widget w,XEvent * event,String * p,Cardinal * n)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
MoveBeginningOfFile(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
MoveEndOfFile(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
Scroll(TextWidget ctx,XEvent * event,XawTextScanDirection dir)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
ScrollOneLineUp(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
ScrollOneLineDown(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)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
MovePage(TextWidget ctx,XEvent * event _X_UNUSED,XawTextScanDirection dir)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
MoveNextPage(Widget w,XEvent * event,String * p,Cardinal * n)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
MovePreviousPage(Widget w,XEvent * event,String * p,Cardinal * n)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
MatchSelection(Atom selection,XawTextSelection * s)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
ConvertSelection(Widget w,Atom * selection,Atom * target,Atom * type,XtPointer * value,unsigned long * length,int * format)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     Arg args[1];
954     XawTextSelectionSalt *salt = NULL;
955     XawTextSelection *s;
956 
957     if (*target == XA_TARGETS(d)) {
958 	Atom *targetP, *std_targets;
959 	unsigned long std_length;
960 
961 	if (SrcCvtSel(src, selection, target, type, value, length, format))
962 	    return (True);
963 
964 	XtSetArg(args[0], XtNeditType,&edit_mode);
965 	XtGetValues(src, args, 1);
966 
967 	XmuConvertStandardSelection(w, ctx->text.time, selection,
968 				    target, type, (XPointer *)&std_targets,
969 				    &std_length, format);
970 
971 	*length = (7 + (unsigned long)(edit_mode == XawtextEdit) + std_length);
972 	*value = XtMalloc((Cardinal)((unsigned)sizeof(Atom)*(*length)));
973 	targetP = *(Atom**)value;
974 	*targetP++ = XA_STRING;
975 	*targetP++ = XA_TEXT(d);
976 	*targetP++ = XA_UTF8_STRING(d);
977 	*targetP++ = XA_COMPOUND_TEXT(d);
978 	*targetP++ = XA_LENGTH(d);
979 	*targetP++ = XA_LIST_LENGTH(d);
980 	*targetP++ = XA_CHARACTER_POSITION(d);
981 	if (edit_mode == XawtextEdit) {
982 	    *targetP++ = XA_DELETE(d);
983 	}
984 	memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
985 	XtFree((char*)std_targets);
986 	*type = XA_ATOM;
987 	*format = 32;
988 	return (True);
989     }
990 
991     if (SrcCvtSel(src, selection, target, type, value, length, format))
992 	return (True);
993 
994     for (salt = ctx->text.salt2; salt; salt = salt->next)
995 	if (MatchSelection (*selection, &salt->s))
996 	    break;
997     if (!salt)
998 	return (False);
999     s = &salt->s;
1000     if (*target == XA_STRING
1001 	|| *target == XA_TEXT(d)
1002 	|| *target == XA_UTF8_STRING(d)
1003 	|| *target == XA_COMPOUND_TEXT(d)) {
1004 	if (*target == XA_TEXT(d)) {
1005 	    if (XawTextFormat(ctx, XawFmtWide))
1006 		*type = XA_COMPOUND_TEXT(d);
1007 	    else
1008 		*type = XA_STRING;
1009 	}
1010 	else
1011 	  *type = *target;
1012 
1013 	/*
1014 	 * If salt is True, the salt->contents stores CT string,
1015 	 * its length is measured in bytes.
1016 	 * Refer to _XawTextSaltAwaySelection()
1017 	 *
1018 	 * by Li Yuhong, Mar. 20, 1991.
1019 	 */
1020 	if (!salt) {
1021 	    *value = (char *)_XawTextGetSTRING(ctx, s->left, s->right);
1022 	    if (XawTextFormat(ctx, XawFmtWide)) {
1023 		XTextProperty textprop;
1024 		if (XwcTextListToTextProperty(d, (wchar_t**)value, 1,
1025 					      XCompoundTextStyle, &textprop)
1026 		    < Success) {
1027 		    XtFree(*value);
1028 		    return (False);
1029 		}
1030 		XtFree(*value);
1031 		*value = (XtPointer)textprop.value;
1032 		*length = textprop.nitems;
1033 	    }
1034 	    else
1035 		*length = strlen(*value);
1036 	}
1037 	else {
1038 	    *value = XtMalloc(((size_t)(salt->length + 1) * sizeof(unsigned char)));
1039 	    strcpy (*value, salt->contents);
1040 	    *length = (unsigned long)salt->length;
1041 	}
1042 	/* Got *value,*length, now in COMPOUND_TEXT format. */
1043 	if (XawTextFormat(ctx, XawFmtWide)) {
1044 	    if (*type == XA_STRING) {
1045 		XTextProperty textprop;
1046 		wchar_t **wlist;
1047 		int count;
1048 
1049 		textprop.encoding = XA_COMPOUND_TEXT(d);
1050 		textprop.value = (unsigned char *)*value;
1051 		textprop.nitems = strlen(*value);
1052 		textprop.format = 8;
1053 		if (XwcTextPropertyToTextList(d, &textprop, &wlist, &count)
1054 		     < Success
1055 		    || count < 1) {
1056 		    XtFree(*value);
1057 		    return (False);
1058 		}
1059 		XtFree(*value);
1060 		if (XwcTextListToTextProperty(d, wlist, 1, XStringStyle, &textprop)
1061 		     < Success) {
1062 		    XwcFreeStringList((wchar_t**)wlist);
1063 		    return (False);
1064 		}
1065 		*value = (XtPointer)textprop.value;
1066 		*length = textprop.nitems;
1067 		XwcFreeStringList((wchar_t**) wlist);
1068 	    }
1069 	    else if (*type == XA_UTF8_STRING(d)) {
1070 		XTextProperty textprop;
1071 		char **list;
1072 		int count;
1073 
1074 		textprop.encoding = XA_COMPOUND_TEXT(d);
1075 		textprop.value = (unsigned char *)*value;
1076 		textprop.nitems = strlen(*value);
1077 		textprop.format = 8;
1078 		if (Xutf8TextPropertyToTextList(d, &textprop, &list, &count)
1079 		    < Success
1080 		    || count < 1) {
1081 		    XtFree(*value);
1082 		    return (False);
1083 		}
1084 		XtFree(*value);
1085 		*value = *list;
1086 		*length = strlen(*list);
1087 		XFree(list);
1088 	    }
1089 	}
1090 	*format = 8;
1091 	return (True);
1092     }
1093 
1094     if (*target == XA_LIST_LENGTH(d) || *target == XA_LENGTH(d)) {
1095 	long *temp;
1096 
1097 	temp = (long *)XtMalloc(sizeof(long));
1098 	if (*target == XA_LIST_LENGTH(d))
1099 	    *temp = 1L;
1100 	else			/* *target == XA_LENGTH(d) */
1101 	    *temp = (long)(s->right - s->left);
1102 
1103 	*value = (XPointer)temp;
1104 	*type = XA_INTEGER;
1105 	*length = 1L;
1106 	*format = 32;
1107 	return (True);
1108     }
1109 
1110     if (*target == XA_CHARACTER_POSITION(d)) {
1111 	long *temp;
1112 
1113 	temp = (long *) XtMalloc(2 * sizeof(long));
1114 	temp[0] = (long)(s->left + 1);
1115 	temp[1] = s->right;
1116 	*value = (XPointer)temp;
1117 	*type = XA_SPAN(d);
1118 	*length = 2L;
1119 	*format = 32;
1120 	return (True);
1121     }
1122 
1123     if (*target == XA_DELETE(d)) {
1124 	if (!salt)
1125 	    _XawTextZapSelection(ctx, NULL, True);
1126 	*value = NULL;
1127 	*type = XA_NULL(d);
1128 	*length = 0;
1129 	*format = 32;
1130 	return (True);
1131     }
1132 
1133     if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
1134 				    (XPointer *)value, length, format))
1135 	return (True);
1136 
1137     return (False);
1138 }
1139 
1140 static void
LoseSelection(Widget w,Atom * selection)1141 LoseSelection(Widget w, Atom *selection)
1142 {
1143     _LoseSelection(w, selection, NULL, NULL);
1144 }
1145 
1146 static void
_LoseSelection(Widget w,Atom * selection,char ** contents _X_UNUSED,int * length _X_UNUSED)1147 _LoseSelection(Widget w, Atom *selection, char **contents _X_UNUSED, int *length _X_UNUSED)
1148 {
1149     TextWidget ctx = (TextWidget)w;
1150     Atom *atomP;
1151     int i;
1152     XawTextSelectionSalt *salt, *prevSalt, *nextSalt;
1153 
1154     prevSalt = 0;
1155     for (salt = ctx->text.salt2; salt; salt = nextSalt) {
1156 	atomP = salt->s.selections;
1157 	nextSalt = salt->next;
1158 	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1159 	    if (*selection == *atomP)
1160 		*atomP = (Atom)0;
1161 
1162 	while (salt->s.atom_count
1163 	       && salt->s.selections[salt->s.atom_count-1] == 0)
1164 	    salt->s.atom_count--;
1165 
1166 	/*
1167 	 * Must walk the selection list in opposite order from UnsetSelection.
1168 	 */
1169 	atomP = salt->s.selections;
1170 	for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
1171 	    if (*atomP == (Atom)0) {
1172 		*atomP = salt->s.selections[--salt->s.atom_count];
1173 
1174 		while (salt->s.atom_count
1175 		       && salt->s.selections[salt->s.atom_count-1] == 0)
1176 		    salt->s.atom_count--;
1177 	    }
1178 	if (salt->s.atom_count == 0) {
1179 #ifndef OLDXAW
1180 	    if (contents == NULL) {
1181 		XawTextKillRing *kill_ring = XtNew(XawTextKillRing);
1182 
1183 		kill_ring->next = xaw_text_kill_ring;
1184 		kill_ring->contents = salt->contents;
1185 		kill_ring->length = salt->length;
1186 		kill_ring->format = XawFmt8Bit;
1187 		xaw_text_kill_ring = kill_ring;
1188 		kill_ring_prev.next = xaw_text_kill_ring;
1189 
1190 		if (++num_kill_rings > MAX_KILL_RINGS) {
1191 		    XawTextKillRing *tail = NULL;
1192 
1193 		    while (kill_ring->next) {
1194 			tail = kill_ring;
1195 			kill_ring = kill_ring->next;
1196 		    }
1197 		    if (kill_ring->refcount == 0) {
1198 			--num_kill_rings;
1199 			tail->next = NULL;
1200 			XtFree(kill_ring->contents);
1201 			XtFree((char*)kill_ring);
1202 		    }
1203 		}
1204 	    }
1205 	    else {
1206 		*contents = salt->contents;
1207 		*length = salt->length;
1208 	    }
1209 #endif
1210 	    if (prevSalt)
1211 		prevSalt->next = nextSalt;
1212 	    else
1213 		ctx->text.salt2 = nextSalt;
1214 
1215 	    XtFree((char *)salt->s.selections);
1216 	    XtFree((char *)salt);
1217 	}
1218 	else
1219 	    prevSalt = salt;
1220     }
1221 }
1222 
1223 static void
_DeleteOrKill(TextWidget ctx,XawTextPosition from,XawTextPosition to,Bool kill)1224 _DeleteOrKill(TextWidget ctx, XawTextPosition from, XawTextPosition to,
1225 	      Bool kill)
1226 {
1227     XawTextBlock text;
1228 
1229 #ifndef OLDXAW
1230     if (ctx->text.kill_ring_ptr) {
1231 	--ctx->text.kill_ring_ptr->refcount;
1232 	ctx->text.kill_ring_ptr = NULL;
1233     }
1234 #endif
1235     if (kill && from < to) {
1236 #ifndef OLDXAW
1237 	Bool append = False;
1238 	char *ring = NULL;
1239 	XawTextPosition old_from = from;
1240 #endif
1241 	char *string;
1242 	int size = 0, length;
1243 	XawTextSelectionSalt *salt;
1244 	Atom selection = XInternAtom(XtDisplay(ctx), "SECONDARY", False);
1245 
1246 #ifndef OLDXAW
1247 	if (ctx->text.kill_ring == KILL_RING_APPEND) {
1248 	    old_from = ctx->text.salt2->s.left;
1249 	    append = True;
1250 	}
1251 	else
1252 	    ctx->text.kill_ring = KILL_RING_BEGIN;
1253 
1254 	if (append)
1255 	    _LoseSelection((Widget)ctx, &selection, &ring, &size);
1256 	else
1257 #endif
1258 	    LoseSelection((Widget)ctx, &selection);
1259 
1260 	salt = (XawTextSelectionSalt*)XtMalloc(sizeof(XawTextSelectionSalt));
1261 	salt->s.selections = (Atom *)XtMalloc(sizeof(Atom));
1262 	salt->s.left = from;
1263 	salt->s.right = to;
1264 
1265 	string = (char *)_XawTextGetSTRING(ctx, from, to);
1266 
1267 	if (XawTextFormat(ctx, XawFmtWide)) {
1268 	    XTextProperty textprop;
1269 
1270 	    if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
1271 					  (wchar_t**)(&string),
1272 					  1, XCompoundTextStyle,
1273 					  &textprop) <  Success) {
1274 		XtFree(string);
1275 		XtFree((char*)salt->s.selections);
1276 		XtFree((char*)salt);
1277 		return;
1278 	    }
1279 	    XtFree(string);
1280 	    string = (char *)textprop.value;
1281 	    length = (int)textprop.nitems;
1282 	}
1283 	else
1284 	    length = (int)strlen(string);
1285 
1286 	salt->length = length + size;
1287 
1288 #ifndef OLDXAW
1289 	if (!append)
1290 	    salt->contents = string;
1291 	else {
1292 	    salt->contents = XtMalloc((length + size + 1));
1293 	    if (from >= old_from) {
1294 		strncpy(salt->contents, ring, (size_t)size);
1295 		salt->contents[size] = '\0';
1296 		strncat(salt->contents, string, (size_t)length);
1297 	    }
1298 	    else {
1299 		strncpy(salt->contents, string, (size_t)length);
1300 		salt->contents[length] = '\0';
1301 		strncat(salt->contents, ring, (size_t)size);
1302 	    }
1303 	    salt->contents[length + size] = '\0';
1304 	    XtFree(ring);
1305 	    XtFree(string);
1306 	}
1307 
1308 	kill_ring_prev.contents = salt->contents;
1309 	kill_ring_prev.length = salt->length;
1310 	kill_ring_prev.format = XawFmt8Bit;
1311 #else
1312 	salt->contents = string;
1313 #endif
1314 
1315 	salt->next = ctx->text.salt2;
1316 	ctx->text.salt2 = salt;
1317 
1318 #ifndef OLDXAW
1319 	if (append)
1320 	    ctx->text.kill_ring = KILL_RING_BEGIN;
1321 #endif
1322 
1323 	salt->s.selections[0] = selection;
1324 
1325 	XtOwnSelection((Widget)ctx, selection, ctx->text.time,
1326 		       ConvertSelection, LoseSelection, NULL);
1327 	salt->s.atom_count = 1;
1328     }
1329     text.length = 0;
1330     text.firstPos = 0;
1331 
1332     text.format = (unsigned long)_XawTextFormat(ctx);
1333     text.ptr = "";
1334 
1335     if (_XawTextReplace(ctx, from, to, &text)) {
1336 	XBell(XtDisplay(ctx), 50);
1337 	return;
1338     }
1339     ctx->text.from_left = -1;
1340     ctx->text.insertPos = from;
1341     ctx->text.showposition = TRUE;
1342 }
1343 
1344 static void
DeleteOrKill(TextWidget ctx,XEvent * event,XawTextScanDirection dir,XawTextScanType type,Bool include,Bool kill)1345 DeleteOrKill(TextWidget ctx, XEvent *event, XawTextScanDirection dir,
1346 	     XawTextScanType type, Bool include, Bool kill)
1347 {
1348     XawTextPosition from, to;
1349     short mult = MULT(ctx);
1350 
1351     if (mult < 0) {
1352 	mult = (short)(-mult);
1353 	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
1354     }
1355 
1356     StartAction(ctx, event);
1357 #ifndef OLDXAW
1358     if (mult == 1)
1359 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
1360 #endif
1361     to = SrcScan(ctx->text.source, ctx->text.insertPos,
1362 		 type, dir, mult, (Boolean)include);
1363 
1364     /*
1365      * If no movement actually happened, then bump the count and try again.
1366      * This causes the character position at the very beginning and end of
1367      * a boundary to act correctly
1368      */
1369     if (to == ctx->text.insertPos)
1370 	to = SrcScan(ctx->text.source, ctx->text.insertPos,
1371 		     type, dir, mult + 1, (Boolean)include);
1372 
1373     if (dir == XawsdLeft) {
1374 	from = to;
1375 	to = ctx->text.insertPos;
1376     }
1377     else
1378 	from = ctx->text.insertPos;
1379 
1380     _DeleteOrKill(ctx, from, to, kill);
1381     EndAction(ctx);
1382 }
1383 
1384 static void
Delete(Widget w,XEvent * event,String * p,Cardinal * n)1385 Delete(Widget w, XEvent *event, String *p, Cardinal *n)
1386 {
1387     TextWidget ctx = (TextWidget)w;
1388 
1389     if (ctx->text.s.left != ctx->text.s.right)
1390 	DeleteCurrentSelection(w, event, p, n);
1391     else
1392 	DeleteBackwardChar(w, event, p, n);
1393 }
1394 
1395 static void
DeleteChar(Widget w,XEvent * event,XawTextScanDirection dir)1396 DeleteChar(Widget w, XEvent *event, XawTextScanDirection dir)
1397 {
1398     TextWidget ctx = (TextWidget)w;
1399     short mul = MULT(ctx);
1400 
1401     if (mul < 0) {
1402 	ctx->text.mult = mul = (short)(-mul);
1403 	dir = dir == XawsdLeft ? XawsdRight : XawsdLeft;
1404     }
1405     DeleteOrKill(ctx, event, dir, XawstPositions, True, False);
1406 #ifndef OLDXAW
1407     if (mul == 1)
1408 	_XawSourceSetUndoErase((TextSrcObject)ctx->text.source,
1409 			       dir == XawsdLeft ? -1 : 1);
1410 #endif
1411 }
1412 
1413 /*ARGSUSED*/
1414 static void
DeleteForwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1415 DeleteForwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1416 {
1417     DeleteChar(w, event, XawsdRight);
1418 }
1419 
1420 /*ARGSUSED*/
1421 static void
DeleteBackwardChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1422 DeleteBackwardChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1423 {
1424     DeleteChar(w, event, XawsdLeft);
1425 }
1426 
1427 static void
DeleteForwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1428 DeleteForwardWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
1429 {
1430     XawTextScanType type;
1431 
1432     if (*num_params && (*params[0] == 'A' || *params[0] == 'a'))
1433 	type = XawstAlphaNumeric;
1434     else
1435 	type = XawstWhiteSpace;
1436 
1437     DeleteOrKill((TextWidget)w, event, XawsdRight, type, False, False);
1438 }
1439 
1440 static void
DeleteBackwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1441 DeleteBackwardWord(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, XawsdLeft, type, False, False);
1451 }
1452 
1453 static void
KillForwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1454 KillForwardWord(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, XawsdRight, type, False, True);
1464 }
1465 
1466 static void
KillBackwardWord(Widget w,XEvent * event,String * params,Cardinal * num_params)1467 KillBackwardWord(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, XawsdLeft, type, False, True);
1477 }
1478 
1479 /*ARGSUSED*/
1480 static void
KillToEndOfLine(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1481 KillToEndOfLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1482 {
1483     TextWidget ctx = (TextWidget)w;
1484     XawTextPosition end_of_line;
1485     XawTextScanDirection dir = XawsdRight;
1486     short mult = MULT(ctx);
1487 
1488     if (mult < 0) {
1489 	dir = XawsdLeft;
1490 	mult = (short)(-mult);
1491     }
1492 
1493     StartAction(ctx, event);
1494     end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
1495 			  dir, mult, False);
1496     if (end_of_line == ctx->text.insertPos)
1497 	end_of_line = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
1498 			      dir, mult, True);
1499 
1500     if (dir == XawsdRight)
1501 	_DeleteOrKill(ctx, ctx->text.insertPos, end_of_line, True);
1502     else
1503 	_DeleteOrKill(ctx, end_of_line, ctx->text.insertPos, True);
1504     EndAction(ctx);
1505 }
1506 
1507 /*ARGSUSED*/
1508 static void
KillToEndOfParagraph(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1509 KillToEndOfParagraph(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1510 {
1511     DeleteOrKill((TextWidget)w, event, XawsdRight, XawstParagraph, False, True);
1512 }
1513 
1514 void
_XawTextZapSelection(TextWidget ctx,XEvent * event,Bool kill)1515 _XawTextZapSelection(TextWidget ctx, XEvent *event, Bool kill)
1516 {
1517     StartAction(ctx, event);
1518     _DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, kill);
1519     EndAction(ctx);
1520 }
1521 
1522 /*ARGSUSED*/
1523 static void
KillCurrentSelection(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1524 KillCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1525 {
1526     _XawTextZapSelection((TextWidget) w, event, True);
1527 }
1528 
1529 #ifndef OLDXAW
1530 /*ARGSUSED*/
1531 static void
KillRingYank(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)1532 KillRingYank(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
1533 {
1534     TextWidget ctx = (TextWidget)w;
1535     XawTextPosition insertPos = ctx->text.insertPos;
1536     Bool first_yank = False;
1537 
1538     if (ctx->text.s.left != ctx->text.s.right)
1539 	XawTextUnsetSelection((Widget)ctx);
1540 
1541     StartAction(ctx, event);
1542 
1543     if (ctx->text.kill_ring_ptr == NULL) {
1544 	ctx->text.kill_ring_ptr = &kill_ring_prev;
1545 	++ctx->text.kill_ring_ptr->refcount;
1546 	ctx->text.s.left = ctx->text.s.right = insertPos;
1547 	first_yank = True;
1548     }
1549     if (ctx->text.kill_ring_ptr) {
1550 	int mul = MULT(ctx);
1551 	XawTextBlock text;
1552 
1553 	if (!first_yank) {
1554 	    if (mul < 0)
1555 		mul = 1;
1556 	    --ctx->text.kill_ring_ptr->refcount;
1557 	    while (mul--) {
1558 		if ((ctx->text.kill_ring_ptr = ctx->text.kill_ring_ptr->next) == NULL)
1559 		    ctx->text.kill_ring_ptr = &kill_ring_null;
1560 	    }
1561 	    ++ctx->text.kill_ring_ptr->refcount;
1562 	}
1563 	text.firstPos = 0;
1564 	text.length = ctx->text.kill_ring_ptr->length;
1565 	text.ptr = ctx->text.kill_ring_ptr->contents;
1566 	text.format = ctx->text.kill_ring_ptr->format;
1567 
1568 	if (_XawTextReplace(ctx, ctx->text.s.left, insertPos, &text) == XawEditDone) {
1569 	    ctx->text.kill_ring = KILL_RING_YANK;
1570 	    ctx->text.insertPos = ctx->text.s.left + text.length;
1571 	}
1572     }
1573     else
1574 	XBell(XtDisplay(w), 0);
1575 
1576     EndAction(ctx);
1577 }
1578 #endif /* OLDXAW */
1579 
1580 /*ARGSUSED*/
1581 static void
DeleteCurrentSelection(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)1582 DeleteCurrentSelection(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
1583 {
1584     _XawTextZapSelection((TextWidget)w, event, False);
1585 }
1586 
1587 #ifndef OLDXAW
1588 #define CHECK_SAVE()						\
1589 	if (save && !save->ptr)					\
1590 	    save->ptr = _XawTextGetText(ctx, save->firstPos,	\
1591 		save->firstPos + save->length)
1592 static Bool
StripSpaces(TextWidget ctx,XawTextPosition left,XawTextPosition right,XawTextPosition * pos,int num_pos,XawTextBlock * save)1593 StripSpaces(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1594 	    XawTextPosition *pos, int num_pos, XawTextBlock *save)
1595 {
1596     Bool done, space;
1597     int i, cpos, count = 0;
1598     XawTextBlock block, text;
1599     XawTextPosition ipos, position = left, tmp = left;
1600 
1601     text.firstPos = 0;
1602     text.format = XawFmt8Bit;
1603     text.ptr = " ";
1604     text.length = 1;
1605 
1606     position = XawTextSourceRead(ctx->text.source, position,
1607 				 &block, (int)(right - left));
1608     done = False;
1609     space = False;
1610     /* convert tabs and returns to spaces */
1611     while (!done) {
1612 	if (XawTextFormat(ctx, XawFmt8Bit)) {
1613 	    for (i = 0; i < block.length; i++)
1614 		if (block.ptr[i] == '\t' || block.ptr[i] == '\n') {
1615 		    space = True;
1616 		    break;
1617 		}
1618 	}
1619 	else {
1620 	    wchar_t *wptr = (wchar_t*)block.ptr;
1621 	    for (i = 0; i < block.length; i++)
1622 		if (wptr[i] == _Xaw_atowc('\t') || wptr[i] == _Xaw_atowc('\n')) {
1623 		    space = True;
1624 		    break;
1625 		}
1626 	}
1627 	if (space) {
1628 	    CHECK_SAVE();
1629 	    if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text))
1630 		return (False);
1631 	    space = False;
1632 	}
1633 	tmp += i;
1634 	position = XawTextSourceRead(ctx->text.source, tmp,
1635 				     &block, (int)(right - tmp));
1636 	if (block.length == 0 || tmp == position || tmp >= right)
1637 	    done = True;
1638     }
1639 
1640     text.ptr = "";
1641     text.length = 0;
1642     position = tmp = left;
1643     position = XawTextSourceRead(ctx->text.source, position,
1644 				 &block, (int)(right - left));
1645     ipos = ctx->text.insertPos;
1646     done = False;
1647     while (!done) {
1648 	if (XawTextFormat(ctx, XawFmt8Bit)) {
1649 	    for (i = 0; i < block.length; i++)
1650 		if (block.ptr[i] == ' ')
1651 		    ++count;
1652 		else if (count == 1)
1653 		    count = 0;
1654 		else if (count)
1655 		    break;
1656 	}
1657 	else {
1658 	    wchar_t *wptr = (wchar_t*)block.ptr;
1659 	    for (i = 0; i < block.length; i++)
1660 		if (wptr[i] == _Xaw_atowc(' '))
1661 		    ++count;
1662 		else if (count == 1)
1663 		    count = 0;
1664 		else if (count)
1665 		    break;
1666 	}
1667 	if (--count > 0) {
1668 	    CHECK_SAVE();
1669 	    if (_XawTextReplace(ctx, tmp + i - count, tmp + i, &text))
1670 		return (False);
1671 	    right -= count;
1672 	    if (num_pos) {
1673 		for (cpos = 0; cpos < num_pos; cpos++) {
1674 		    if (tmp + i - count < pos[cpos]) {
1675 			if (tmp + i < pos[cpos])
1676 			    pos[cpos] -= count;
1677 			else
1678 			    pos[cpos] = tmp + i - count;
1679 		    }
1680 		}
1681 	    }
1682 	    else {
1683 		if (tmp + i - count < ipos) {
1684 		    if (tmp + i < ipos)
1685 			ipos -= count;
1686 		    else
1687 			ipos = tmp + i - count;
1688 		}
1689 	    }
1690 	    tmp += i - count;
1691 	}
1692 	else
1693 	    tmp += i + 1;
1694 	count = 0;
1695 	position = XawTextSourceRead(ctx->text.source, tmp,
1696 				     &block, (int)(right - tmp));
1697 	if (block.length == 0 || tmp == position || tmp >= right)
1698 	    done = True;
1699     }
1700     if (!num_pos)
1701 	ctx->text.insertPos = ipos;
1702 
1703     return (True);
1704 }
1705 
1706 static Bool
Tabify(TextWidget ctx,XawTextPosition left,XawTextPosition right,XawTextPosition * pos,int num_pos,XawTextBlock * save)1707 Tabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1708        XawTextPosition *pos, int num_pos, XawTextBlock *save)
1709 {
1710     Bool done, zero;
1711     int i, cpos, count = 0, column = 0, offset = 0;
1712     XawTextBlock text, block;
1713     XawTextPosition ipos, position = left, tmp = left;
1714     TextSinkObject sink = (TextSinkObject)ctx->text.sink;
1715     short *char_tabs = sink->text_sink.char_tabs;
1716     int tab_count = sink->text_sink.tab_count;
1717     int tab_index = 0, tab_column = 0, TAB_SIZE = DEFAULT_TAB_SIZE;
1718 
1719     text.firstPos = 0;
1720     text.ptr = "\t";
1721     text.format = XawFmt8Bit;
1722     text.length = 1;
1723 
1724     position = XawTextSourceRead(ctx->text.source, position,
1725 				 &block, (int)(right - left));
1726     ipos = ctx->text.insertPos;
1727     done = zero = False;
1728     if (tab_count)
1729 	TAB_SIZE = *char_tabs;
1730     while (!done) {
1731 	if (XawTextFormat(ctx, XawFmt8Bit)) {
1732 	    for (i = 0; i < block.length; i++) {
1733 		++offset;
1734 		++column;
1735 		if (tab_count) {
1736 		    if (column > tab_column + char_tabs[tab_index]) {
1737 			TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
1738 			if (++tab_index >= tab_count) {
1739 			    tab_column += char_tabs[tab_count - 1];
1740 			    tab_index = 0;
1741 			}
1742 		    }
1743 		}
1744 		if (block.ptr[i] == ' ') {
1745 		    if (++count > TAB_SIZE)
1746 			count %= TAB_SIZE;
1747 		    if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
1748 			(!tab_count && column % TAB_SIZE == 0)) {
1749 			if (count % (TAB_SIZE + 1) > 1)
1750 			    break;
1751 			else
1752 			    count = 0;
1753 		    }
1754 		}
1755 		else {
1756 		    if (block.ptr[i] == '\n') {
1757 			zero = True;
1758 			break;
1759 		    }
1760 		    count = 0;
1761 		}
1762 	    }
1763 	}
1764 	else {
1765 	    wchar_t *wptr = (wchar_t*)block.ptr;
1766 	    for (i = 0; i < block.length; i++) {
1767 		++offset;
1768 		++column;
1769 		if (tab_count) {
1770 		    if (column > tab_column + char_tabs[tab_index]) {
1771 			TAB_SIZE = tab_index < tab_count - 1 ? char_tabs[tab_index + 1] - char_tabs[tab_index] : *char_tabs;
1772 			if (++tab_index >= tab_count) {
1773 			    tab_column += char_tabs[tab_count - 1];
1774 			    tab_index = 0;
1775 			}
1776 		    }
1777 		}
1778 		if (wptr[i] == _Xaw_atowc(' ')) {
1779 		    if (++count > TAB_SIZE)
1780 			count %= TAB_SIZE;
1781 		    if ((tab_count && column == tab_column + char_tabs[tab_index]) ||
1782 			(!tab_count && column % TAB_SIZE == 0)) {
1783 			if (count % (TAB_SIZE + 1) > 1)
1784 			    break;
1785 			else
1786 			    count = 0;
1787 		    }
1788 		}
1789 		else {
1790 		    if (wptr[i] == _Xaw_atowc('\n')) {
1791 			zero = True;
1792 			break;
1793 		    }
1794 		    count = 0;
1795 		}
1796 	    }
1797 	}
1798 	count %= TAB_SIZE + 1;
1799 	if (!zero && count > 1 && i < block.length) {
1800 	    CHECK_SAVE();
1801 	    if (_XawTextReplace(ctx, tmp + i - count + 1, tmp + i + 1, &text))
1802 		return (False);
1803 	    right -= count - 1;
1804 	    offset -= count - 1;
1805 	    if (num_pos) {
1806 		for (cpos = 0; cpos < num_pos; cpos++) {
1807 		    if (tmp + i - count + 1 < pos[cpos]) {
1808 			if (tmp + i + 1 < pos[cpos])
1809 			    pos[cpos] -= count;
1810 			else
1811 			    pos[cpos] = tmp + i - count + 1;
1812 			++pos[cpos];
1813 		    }
1814 		}
1815 	    }
1816 	    else {
1817 		if (tmp + i - count + 1 < ipos) {
1818 		    if (tmp + i + 1 < ipos)
1819 			ipos -= count;
1820 		    else
1821 			ipos = tmp + i - count + 1;
1822 		    ++ipos;
1823 		}
1824 	    }
1825 	}
1826 	if (count)
1827 	    --count;
1828 	if (zero) {
1829 	    count = column = 0;
1830 	    zero = False;
1831 	    if (tab_count) {
1832 		tab_column = tab_index = 0;
1833 		TAB_SIZE = *char_tabs;
1834 	    }
1835 	}
1836 	else if (i < block.length)
1837 	    count = 0;
1838 	tmp = left + offset;
1839 	position = XawTextSourceRead(ctx->text.source, tmp,
1840 				     &block, (int)(right - tmp));
1841 	if (tmp == position || tmp >= right)
1842 	    done = True;
1843     }
1844     if (!num_pos)
1845 	ctx->text.insertPos = ipos;
1846 
1847     return (True);
1848 }
1849 
1850 static Bool
Untabify(TextWidget ctx,XawTextPosition left,XawTextPosition right,XawTextPosition * pos,int num_pos,XawTextBlock * save)1851 Untabify(TextWidget ctx, XawTextPosition left, XawTextPosition right,
1852 	 XawTextPosition *pos, int num_pos, XawTextBlock *save)
1853 {
1854     Bool done, zero;
1855     int i, cpos, count = 0, diff = 0;
1856     XawTextBlock block, text;
1857     XawTextPosition ipos, position = left, tmp = left;
1858     TextSinkObject sink = (TextSinkObject)ctx->text.sink;
1859     short *char_tabs = sink->text_sink.char_tabs;
1860     int tab_count = sink->text_sink.tab_count;
1861     int tab_index = 0, tab_column = 0, tab_base = 0;
1862     static char *tabs = "        ";
1863 
1864     text.firstPos = 0;
1865     text.format = XawFmt8Bit;
1866     text.ptr = tabs;
1867 
1868     position = XawTextSourceRead(ctx->text.source, position,
1869 				 &block, (int)(right - left));
1870     ipos = ctx->text.insertPos;
1871     done = False;
1872     zero = False;
1873     while (!done) {
1874 	if (XawTextFormat(ctx, XawFmt8Bit))
1875 	    for (i = 0; i < block.length; i++) {
1876 		if (block.ptr[i] != '\t') {
1877 		    ++count;
1878 		    if (block.ptr[i] == '\n') {
1879 			zero = True;
1880 			break;
1881 		    }
1882 		}
1883 		else
1884 		    break;
1885 	}
1886 	else {
1887 	    wchar_t *wptr = (wchar_t*)block.ptr;
1888 	    for (i = 0; i < block.length; i++)
1889 		if (wptr[i] != _Xaw_atowc('\t')) {
1890 		    ++count;
1891 		    if (wptr[i] != _Xaw_atowc('\n')) {
1892 			zero = True;
1893 			break;
1894 		    }
1895 		}
1896 		else
1897 		    break;
1898 	}
1899 	if (!zero && i < block.length) {
1900 	    if (tab_count) {
1901 		while (tab_base + tab_column <= count) {
1902 		    for (; tab_index < tab_count; ++tab_index)
1903 			if (tab_base + char_tabs[tab_index] > count) {
1904 			    tab_column = char_tabs[tab_index];
1905 			    break;
1906 			}
1907 		    if (tab_index >= tab_count) {
1908 			tab_base += char_tabs[tab_count - 1];
1909 			tab_column = tab_index = 0;
1910 		    }
1911 		}
1912 		text.length = (tab_base + tab_column) - count;
1913 		if (text.length > 8) {
1914 		    int j;
1915 
1916 		    text.ptr = XtMalloc((Cardinal)text.length);
1917 		    for (j = 0; j < text.length; j++)
1918 			text.ptr[j] = ' ';
1919 		}
1920 		else
1921 		    text.ptr = tabs;
1922 	    }
1923 	    else
1924 		text.length = DEFAULT_TAB_SIZE - (count % DEFAULT_TAB_SIZE);
1925 	    CHECK_SAVE();
1926 	    if (_XawTextReplace(ctx, tmp + i, tmp + i + 1, &text)) {
1927 		if (tab_count && text.length > 8)
1928 		    XtFree(text.ptr);
1929 		return (False);
1930 	    }
1931 	    if (tab_count && text.length > 8)
1932 		XtFree(text.ptr);
1933 	    count += text.length;
1934 	    right += text.length - 1;
1935 	    if (num_pos) {
1936 		for (cpos = 0; cpos < num_pos; cpos++) {
1937 		    if (tmp + i < pos[cpos]) {
1938 			if (tmp + i + 1 < pos[cpos])
1939 			    --pos[cpos];
1940 			else
1941 			    pos[cpos] = tmp + i;
1942 			pos[cpos] += text.length;
1943 		    }
1944 		}
1945 	    }
1946 	    else {
1947 		if (tmp + i < ipos) {
1948 		    if (tmp + i + 1 < ipos)
1949 			--ipos;
1950 		    else
1951 			ipos = tmp + i;
1952 		    ipos += text.length;
1953 		}
1954 	    }
1955 	}
1956 	tmp = left + count + diff;
1957 	if (zero) {
1958 	    diff += count;
1959 	    count = 0;
1960 	    zero = False;
1961 	    if (tab_count)
1962 		tab_base = tab_column = tab_index = 0;
1963 	}
1964 	position = XawTextSourceRead(ctx->text.source, tmp,
1965 				     &block, (int)(right - tmp));
1966 	if (tmp == position || tmp >= right)
1967 	    done = True;
1968     }
1969     if (!num_pos)
1970 	ctx->text.insertPos = ipos;
1971 
1972     return (True);
1973 }
1974 
1975 static int
FormatText(TextWidget ctx,XawTextPosition left,Bool force,XawTextPosition * pos,int num_pos)1976 FormatText(TextWidget ctx, XawTextPosition left, Bool force,
1977 	   XawTextPosition *pos, int num_pos)
1978 {
1979     char *ptr = NULL;
1980     Bool freepos = False, undo, paragraph = pos != NULL;
1981     int i, result;
1982     XawTextBlock block, *text;
1983     XawTextPosition end = ctx->text.lastPos, buf[32];
1984     TextSrcObject src = (TextSrcObject)ctx->text.source;
1985     XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
1986 				    XawsdRight, 1, False);
1987 
1988     undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
1989     if (undo) {
1990 	if (!pos) {
1991 	    num_pos = (int)src->textSrc.num_text;
1992 	    pos = (XawStackAlloc(sizeof(XawTextPosition) * (size_t)num_pos, buf));
1993 	    for (i = 0; i < num_pos; i++)
1994 		pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
1995 	    freepos = True;
1996 	}
1997 	else
1998 	    freepos = False;
1999 	src->textSrc.undo_state = True;
2000 	block.ptr = NULL;
2001 	block.firstPos = (int)left;
2002 	block.length = (int)(right - left);
2003 	text = &block;
2004     }
2005     else
2006 	text = NULL;
2007 
2008     result = DoFormatText(ctx, left, force, 1, text, pos, num_pos, paragraph);
2009     if (undo && result == XawEditDone && block.ptr) {
2010 	char *lbuf, *rbuf;
2011 	unsigned llen, rlen, size;
2012 
2013 	ptr = lbuf = block.ptr;
2014 	llen = (unsigned)block.length;
2015 	rlen = (unsigned)(llen + (ctx->text.lastPos - end));
2016 
2017 	block.firstPos = 0;
2018 	block.format = (unsigned long)_XawTextFormat(ctx);
2019 
2020 	rbuf = _XawTextGetText(ctx, left, left + rlen);
2021 
2022 	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
2023 	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
2024 	    block.ptr = lbuf;
2025 	    block.length = (int)llen;
2026 	    _XawTextReplace(ctx, left, left + rlen, &block);
2027 
2028 	    src->textSrc.undo_state = False;
2029 	    block.ptr = rbuf;
2030 	    block.length = (int)rlen;
2031 	    _XawTextReplace(ctx, left, left + llen, &block);
2032 	}
2033 	else
2034 	    src->textSrc.undo_state = False;
2035 	XtFree(rbuf);
2036     }
2037     if (undo) {
2038 	src->textSrc.undo_state = False;
2039 	if (freepos) {
2040 	    for (i = 0; i < num_pos; i++) {
2041 		TextWidget tw = (TextWidget)src->textSrc.text[i];
2042 		tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
2043 	    }
2044 	    XawStackFree(pos, buf);
2045 	}
2046 	if (ptr)
2047 	    XtFree(ptr);
2048     }
2049 
2050     return (result);
2051 }
2052 
2053 static int
DoFormatText(TextWidget ctx,XawTextPosition left,Bool force,int level,XawTextBlock * save,XawTextPosition * pos,int num_pos,Bool paragraph)2054 DoFormatText(TextWidget ctx, XawTextPosition left, Bool force, int level,
2055 	     XawTextBlock *save, XawTextPosition *pos, int num_pos,
2056 	     Bool paragraph)
2057 {
2058     XawTextPosition right = SrcScan(ctx->text.source, left, XawstEOL,
2059 				    XawsdRight, 1, False);
2060     XawTextPosition position, tmp, ipos;
2061     XawTextBlock block, text;
2062     char buf[128];
2063     wchar_t *wptr;
2064     int i, count, cpos;
2065     Bool done, force2 = force, recurse = False;
2066 
2067     position = XawTextSourceRead(ctx->text.source, left, &block, (int)(right - left));
2068     if (block.length == 0 || left >= right ||
2069 	(level == 1 && ((XawTextFormat(ctx, XawFmt8Bit) &&
2070 	 block.ptr[0] != ' ' &&
2071 	 block.ptr[0] != '\t' &&
2072 	 !isalnum(*(unsigned char*)block.ptr)) ||
2073 	(XawTextFormat(ctx, XawFmtWide) &&
2074 	 _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
2075 	 _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
2076 	 !iswalnum((wint_t)*(wchar_t*)block.ptr)))))
2077 	return (XawEditDone);
2078 
2079     if (level == 1 && !paragraph) {
2080 	tmp = ctx->text.lastPos;
2081 	if (Untabify(ctx, left, right, pos, num_pos, save) == False)
2082 	    return (XawEditError);
2083 	right += ctx->text.lastPos - tmp;
2084 	position = XawTextSourceRead(ctx->text.source, left, &block,
2085 				     (int)(right - left));
2086     }
2087 
2088     text.firstPos = 0;
2089     text.format = XawFmt8Bit;
2090 
2091     ipos = ctx->text.insertPos;
2092     count = 0;
2093     done = False;
2094     while (!done) {
2095 	if (XawTextFormat(ctx, XawFmt8Bit)) {
2096 	    for (i = 0; i < block.length; i++)
2097 		if (block.ptr[i] == ' ')
2098 		    ++count;
2099 		else {
2100 		    done = True;
2101 		    break;
2102 		}
2103 	}
2104 	else {
2105 	    wptr = (wchar_t*)block.ptr;
2106 	    for (i = 0; i < block.length; i++)
2107 		if (wptr[i] == _Xaw_atowc(' '))
2108 		    ++count;
2109 		else {
2110 		    done = True;
2111 		    break;
2112 		}
2113 	}
2114 	tmp = position;
2115 	position = XawTextSourceRead(ctx->text.source, position,
2116 				     &block, (int)(right - position));
2117 	if (tmp == position)
2118 	    done = True;
2119     }
2120     position = left + count;
2121     if (count < ctx->text.left_column) {
2122 	int bytes = ctx->text.left_column - count;
2123 
2124 	text.ptr = XawStackAlloc((unsigned)bytes, buf);
2125 	text.length = bytes;
2126 	for (i = 0; i < bytes; i++)
2127 	    text.ptr[i] = ' ';
2128 	CHECK_SAVE();
2129 	if (_XawTextReplace(ctx, left, left, &text)) {
2130 	    XawStackFree(text.ptr, buf);
2131 	    return (XawEditError);
2132 	}
2133 	XawStackFree(text.ptr, buf);
2134 	right += bytes;
2135 	if (num_pos) {
2136 	    for (cpos = 0; cpos < num_pos; cpos++)
2137 		if (pos[cpos] >= left)
2138 		    pos[cpos] += bytes;
2139 	}
2140 	if (ipos >= left)
2141 	    ipos += bytes;
2142 	count += bytes;
2143     }
2144 
2145     done = False;
2146     if (!paragraph && level == 1
2147 	&& ipos <= right && ipos - left > ctx->text.right_column) {
2148 	XawTextPosition len = ctx->text.lastPos;
2149 	int skip = ctx->text.justify == XawjustifyRight
2150 		|| ctx->text.justify == XawjustifyCenter ?
2151 		ctx->text.left_column : count;
2152 
2153 	if (pos)
2154 	    for (i = 0; i < num_pos; i++)
2155 		if (pos[i] == ipos)
2156 		    break;
2157 
2158 	StripSpaces(ctx, left + skip, right, pos, num_pos, save);
2159 	right += ctx->text.lastPos - len;
2160 	if (pos && i < num_pos)
2161 	    ipos = pos[i];
2162 	else
2163 	    ipos = ctx->text.insertPos;
2164 	done = ipos - left > ctx->text.right_column;
2165 	count = skip + (count == skip + 1);
2166     }
2167     if ((paragraph || done) && right - left > ctx->text.right_column) {
2168 	position = tmp = right;
2169 	XawTextSourceRead(ctx->text.source, position - 1, &block, 1);
2170 	if (block.length &&
2171 	    ((XawTextFormat(ctx, XawFmt8Bit) &&
2172 	     block.ptr[0] == ' ') ||
2173 	    (XawTextFormat(ctx, XawFmtWide) &&
2174 	     _Xaw_atowc(XawSP) == *(wchar_t*)block.ptr)))
2175 	    --position;
2176 	while (position - left > ctx->text.right_column) {
2177 	    tmp = position;
2178 	    position = SrcScan(ctx->text.source, position,
2179 			       XawstWhiteSpace, XawsdLeft, 1, True);
2180 	}
2181 	if (position <= left + ctx->text.left_column)
2182 	    position = tmp;
2183 	if (position > left && position - left > ctx->text.left_column
2184 	    && position != right) {
2185 	    text.ptr = "\n";
2186 	    text.length = 1;
2187 	    CHECK_SAVE();
2188 	    if (_XawTextReplace(ctx, position, position + 1, &text))
2189 		return (XawEditError);
2190 	    right = position;
2191 	    recurse = True;
2192 	    force = True;
2193 	}
2194     }
2195 
2196     if (force) {
2197 	if (ctx->text.justify == XawjustifyCenter)
2198 	    count = ctx->text.right_column - (count - ctx->text.left_column);
2199 	else
2200 	    count = ctx->text.right_column;
2201 	if (count > right - left)
2202 	    count = (int)(count - (right - left));
2203 	else
2204 	    count = 0;
2205     }
2206     else
2207 	count = 0;
2208     if (count > 0) {
2209 	switch (ctx->text.justify) {
2210 	    case XawjustifyLeft:
2211 		break;
2212 	    case XawjustifyRight:
2213 	    case XawjustifyCenter:
2214 		if (ctx->text.justify == XawjustifyCenter) {
2215 		    int alnum = 0;
2216 
2217 		    if (!(count & 1)) {
2218 			XawTextSourceRead(ctx->text.source, right, &block, 1);
2219 			if ((XawTextFormat(ctx, XawFmt8Bit)
2220 			     && isalnum(*(unsigned char*)block.ptr)) ||
2221 			    (XawTextFormat(ctx, XawFmtWide)
2222 			     && iswalnum((wint_t)*(wchar_t*)block.ptr)))
2223 			    alnum = 1;
2224 		    }
2225 		    count = (count + alnum) >> 1;
2226 		}
2227 		text.ptr = XawStackAlloc((unsigned)count, buf);
2228 		text.length = count;
2229 		for (i = 0; i < count; i++)
2230 		    text.ptr[i] = ' ';
2231 		CHECK_SAVE();
2232 		if (_XawTextReplace(ctx, left, left, &text)) {
2233 		    XawStackFree(text.ptr, buf);
2234 		    return (XawEditError);
2235 		}
2236 		XawStackFree(text.ptr, buf);
2237 		position += count;
2238 		right += count;
2239 		if (num_pos) {
2240 		    for (cpos = 0; cpos < num_pos; cpos++)
2241 			if (pos[cpos] > left)
2242 			    pos[cpos] += count;
2243 		}
2244 		else if (ipos > left)
2245 		    ipos += count;
2246 		break;
2247 	    case XawjustifyFull:
2248 		i = 0;
2249 		tmp = left;
2250 		/*CONSTCOND*/
2251 		while (True) {
2252 		    tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
2253 				  XawsdRight, 1, True);
2254 		    if (tmp < right)
2255 			++i;
2256 		    else
2257 			break;
2258 		}
2259 		if (i) {
2260 		    double inc, ii;
2261 		    int bytes, steps;
2262 
2263 		    bytes = count;
2264 		    inc = ii = (count + .5) / (double)i;
2265 
2266 		    steps = count;
2267 		    text.ptr = XawStackAlloc((unsigned)steps, buf);
2268 		    for (i = 0; i < steps; i++)
2269 			text.ptr[i] = ' ';
2270 		    tmp = left;
2271 		    CHECK_SAVE();
2272 		    while (bytes) {
2273 			steps = 1;
2274 			while (inc + ii < 1) {
2275 			    ++steps;
2276 			    inc += ii;
2277 			}
2278 			tmp = SrcScan(ctx->text.source, tmp, XawstWhiteSpace,
2279 				      XawsdRight, steps, True);
2280 			if (bytes > inc)
2281 			    text.length = (int)inc;
2282 			else
2283 			    text.length = bytes;
2284 			bytes -= text.length;
2285 			if (_XawTextReplace(ctx, tmp, tmp, &text)) {
2286 			    XawStackFree(text.ptr, buf);
2287 			    return (XawEditError);
2288 			}
2289 			if (num_pos) {
2290 			    for (cpos = 0; cpos < num_pos; cpos++)
2291 				if (tmp <= pos[cpos])
2292 				    pos[cpos] += text.length;
2293 			}
2294 			else if (tmp <= ipos)
2295 			    ipos += text.length;
2296 			inc -= (int)inc;
2297 			inc += ii;
2298 		    }
2299 		    position += count;
2300 		    right += count;
2301 		    XawStackFree(text.ptr, buf);
2302 		}
2303 		break;
2304 	}
2305     }
2306 
2307     if (!num_pos)
2308 	ctx->text.insertPos = XawMin(ipos, ctx->text.lastPos);
2309 
2310     return (recurse ? DoFormatText(ctx, position + 1,
2311 				   ctx->text.justify != XawjustifyFull
2312 				   && (force2 || paragraph),
2313 				   ++level, save, pos, num_pos, paragraph)
2314 		 : XawEditDone);
2315 }
2316 #undef CHECK_SAVE
2317 
2318 /*ARGSUSED*/
2319 static void
Indent(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2320 Indent(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2321 {
2322     TextWidget ctx = (TextWidget)w;
2323     TextSrcObject src = (TextSrcObject)ctx->text.source;
2324     XawTextPosition from, to, tmp, end = 0, *pos, *posbuf[32];
2325     char buf[32];
2326     XawTextBlock text;
2327     int i, spaces = MULT(ctx);
2328     char *lbuf = NULL, *rbuf;
2329     unsigned llen = 0, rlen, size;
2330     Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
2331     Bool format = ctx->text.auto_fill
2332 	&& ctx->text.left_column < ctx->text.right_column;
2333 
2334     text.firstPos = 0;
2335     text.format = XawFmt8Bit;
2336     text.ptr = "";
2337 
2338     StartAction(ctx, event);
2339 
2340     pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, posbuf);
2341     for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
2342 	pos[i] = ((TextWidget)src->textSrc.text[i])->text.insertPos;
2343 
2344     if (!GetBlockBoundaries(ctx, &from, &to)) {
2345 	EndAction(ctx);
2346 	XawStackFree(pos, posbuf);
2347 	return;
2348     }
2349 
2350     if (undo) {
2351 	llen = (unsigned)(to - from);
2352 	end = ctx->text.lastPos;
2353 	lbuf = _XawTextGetText(ctx, from, to);
2354 	src->textSrc.undo_state = True;
2355     }
2356 
2357     tmp = ctx->text.lastPos;
2358     if (!Untabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL)) {
2359 	XBell(XtDisplay(ctx), 0);
2360 	EndAction(ctx);
2361 	XawStackFree(pos, posbuf);
2362 	if (undo) {
2363 	    src->textSrc.undo_state = True;
2364 	    XtFree(lbuf);
2365 	}
2366 	return;
2367     }
2368     to += ctx->text.lastPos - tmp;
2369 
2370     tmp = from;
2371 
2372     if (spaces > 0) {
2373 	text.ptr = XawStackAlloc((unsigned)spaces, buf);
2374 	for (i = 0; i < spaces; i++)
2375 	    text.ptr[i] = ' ';
2376 
2377 	text.length = spaces;
2378 	while (tmp < to) {
2379 	    _XawTextReplace(ctx, tmp, tmp, &text);
2380 
2381 	    for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
2382 		if (tmp < pos[i])
2383 		    pos[i] += spaces;
2384 
2385 	    to += spaces;
2386 	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2387 	}
2388 	XawStackFree(text.ptr, buf);
2389     }
2390     else {
2391 	int min = 32767;
2392 
2393 	text.length = 0;
2394 	tmp = from;
2395 
2396 	/* find the amount of spaces to cut */
2397 	while (tmp < to) {
2398 	    (void)BlankLine(w, tmp, &i);
2399 	    if (i < min)
2400 		min = i;
2401 	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2402 	}
2403 	spaces = XawMin(-spaces, min);
2404 
2405 	/* cut the spaces */
2406 	tmp = from;
2407 	while (tmp < to) {
2408 	    _XawTextReplace(ctx, tmp, tmp + spaces, &text);
2409 
2410 	    for (i = 0; (Cardinal)i < src->textSrc.num_text; i++)
2411 		if (tmp < pos[i]) {
2412 		    if (tmp + spaces < pos[i])
2413 			pos[i] -= spaces;
2414 		    else
2415 			pos[i] = tmp;
2416 		}
2417 
2418 	    to -= spaces;
2419 	    tmp = SrcScan(ctx->text.source, tmp, XawstEOL, XawsdRight, 1, True);
2420 	}
2421     }
2422 
2423     if (!format)
2424 	Tabify(ctx, from, to, pos, (int)src->textSrc.num_text, NULL);
2425 
2426     if (undo) {
2427 	rlen = (unsigned)(llen + (ctx->text.lastPos - end));
2428 	rbuf = _XawTextGetText(ctx, from, from + rlen);
2429 
2430 	text.format = (unsigned long)_XawTextFormat(ctx);
2431 	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
2432 	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
2433 	    text.ptr = lbuf;
2434 	    text.length = (int)llen;
2435 	    _XawTextReplace(ctx, from, from + rlen, &text);
2436 
2437 	    src->textSrc.undo_state = False;
2438 	    text.ptr = rbuf;
2439 	    text.length = (int)rlen;
2440 	    _XawTextReplace(ctx, from, from + llen, &text);
2441 	}
2442 	else
2443 	    src->textSrc.undo_state = False;
2444 	XtFree(lbuf);
2445 	XtFree(rbuf);
2446     }
2447 
2448     for (i = 0; (Cardinal)i < src->textSrc.num_text; i++) {
2449 	TextWidget tw = (TextWidget)src->textSrc.text[i];
2450 
2451 	tw->text.insertPos = XawMin(XawMax(0, pos[i]), tw->text.lastPos);
2452     }
2453     XawStackFree(pos, posbuf);
2454     ctx->text.showposition = True;
2455 
2456     EndAction(ctx);
2457 }
2458 
2459 /*ARGSUSED*/
2460 static void
ToggleOverwrite(Widget w,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2461 ToggleOverwrite(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2462 {
2463     TextWidget ctx = (TextWidget)w;
2464 
2465     ctx->text.overwrite = !ctx->text.overwrite;
2466 
2467     /* call information callback */
2468     _XawTextSetLineAndColumnNumber(ctx, True);
2469 }
2470 #endif /* OLDXAW */
2471 
2472 /*
2473  * Insertion Routines
2474  */
2475 static int
InsertNewLineAndBackupInternal(TextWidget ctx)2476 InsertNewLineAndBackupInternal(TextWidget ctx)
2477 {
2478     int count, error = XawEditDone, mult = MULT(ctx);
2479 #ifndef OLDXAW
2480     XawTextPosition position;
2481 #endif
2482     XawTextBlock text;
2483     char buf[32];
2484 
2485     if (mult < 0) {
2486 	ctx->text.mult = 1;
2487 	return (XawEditError);
2488     }
2489 
2490     text.format = (unsigned long)_XawTextFormat(ctx);
2491     text.length = mult;
2492     text.firstPos = 0;
2493 
2494     if (text.format == XawFmtWide) {
2495 	wchar_t *wptr;
2496 
2497 	text.ptr = (XawStackAlloc(sizeof(wchar_t) * (size_t)mult, buf));
2498 	wptr = (wchar_t *)text.ptr;
2499 	for (count = 0; count < mult; count++)
2500 	    wptr[count] = _Xaw_atowc(XawLF);
2501     }
2502     else {
2503 	text.ptr = (XawStackAlloc(sizeof(char) * (size_t)mult, buf));
2504 	for (count = 0; count < mult; count++)
2505 	    text.ptr[count] = XawLF;
2506     }
2507 
2508 #ifndef OLDXAW
2509     position = SrcScan(ctx->text.source, ctx->text.insertPos,
2510 		       XawstEOL, XawsdLeft, 1, False);
2511 #endif
2512     if (_XawTextReplace(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
2513 	XBell( XtDisplay(ctx), 50);
2514 	error = XawEditError;
2515     }
2516     else {
2517 	ctx->text.showposition = TRUE;
2518 	ctx->text.insertPos += text.length;
2519     }
2520 
2521     XawStackFree(text.ptr, buf);
2522 
2523 #ifndef OLDXAW
2524     if (ctx->text.auto_fill && error == XawEditDone)
2525 	(void)FormatText(ctx, position, ctx->text.justify != XawjustifyFull,
2526 			 NULL, 0);
2527 #endif
2528 
2529     return (error);
2530 }
2531 
2532 /*ARGSUSED*/
2533 static void
InsertNewLineAndBackup(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2534 InsertNewLineAndBackup(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2535 {
2536     TextWidget ctx = (TextWidget)w;
2537     XawTextPosition insertPos = ctx->text.insertPos;
2538 
2539     StartAction((TextWidget)w, event);
2540     (void)InsertNewLineAndBackupInternal(ctx);
2541     ctx->text.insertPos = SrcScan(ctx->text.source, insertPos, XawstEOL,
2542 				  XawsdRight, 1, False);
2543     EndAction((TextWidget)w);
2544 }
2545 
2546 static int
LocalInsertNewLine(TextWidget ctx,XEvent * event)2547 LocalInsertNewLine(TextWidget ctx, XEvent *event)
2548 {
2549     int error;
2550 
2551     StartAction(ctx, event);
2552     error = InsertNewLineAndBackupInternal(ctx);
2553     ctx->text.from_left = -1;
2554     EndAction(ctx);
2555 
2556     return (error);
2557 }
2558 
2559 /*ARGSUSED*/
2560 static void
InsertNewLine(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2561 InsertNewLine(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2562 {
2563     (void)LocalInsertNewLine((TextWidget)w, event);
2564 }
2565 
2566 /*ARGSUSED*/
2567 static void
InsertNewLineAndIndent(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2568 InsertNewLineAndIndent(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2569 {
2570     XawTextBlock text;
2571     XawTextPosition pos1;
2572     int length;
2573     TextWidget ctx = (TextWidget)w;
2574     char * line_to_ip;
2575 
2576     StartAction(ctx, event);
2577     pos1 = SrcScan(ctx->text.source, ctx->text.insertPos,
2578 		   XawstEOL, XawsdLeft, 1, False);
2579 
2580     line_to_ip = _XawTextGetText(ctx, pos1, ctx->text.insertPos);
2581 
2582     text.format = (unsigned long)_XawTextFormat(ctx);
2583     text.firstPos = 0;
2584 
2585     if (text.format == XawFmtWide) {
2586 	wchar_t *ptr;
2587 
2588 	text.ptr = XtMalloc((Cardinal)((2 + wcslen((wchar_t*)line_to_ip))
2589 			    * sizeof(wchar_t)));
2590 	ptr = (wchar_t*)text.ptr;
2591 	ptr[0] = _Xaw_atowc(XawLF);
2592 	wcscpy((wchar_t*)++ptr, (wchar_t*)line_to_ip);
2593 
2594 	length = (int)wcslen((wchar_t*)text.ptr);
2595 	while (length && (iswspace(*ptr) || *ptr == _Xaw_atowc(XawTAB)))
2596 	  ptr++, length--;
2597 	*ptr = (wchar_t)0;
2598 	text.length = (int)wcslen((wchar_t*)text.ptr);
2599     }
2600     else {
2601 	char *ptr;
2602 
2603 	length = (int)strlen(line_to_ip);
2604 	text.ptr = XtMalloc(((size_t)(2 + length) * sizeof(char)));
2605 	ptr = text.ptr;
2606 	ptr[0] = XawLF;
2607 	strcpy(++ptr, line_to_ip);
2608 
2609 	length++;
2610 	while (length && (isspace(*ptr) || (*ptr == XawTAB)))
2611 	    ptr++, length--;
2612 	*ptr = '\0';
2613 	text.length = (int)strlen(text.ptr);
2614     }
2615     XtFree(line_to_ip);
2616 
2617     if (_XawTextReplace(ctx,ctx->text.insertPos, ctx->text.insertPos, &text)) {
2618 	XBell(XtDisplay(ctx), 50);
2619 	XtFree(text.ptr);
2620 	EndAction(ctx);
2621 	return;
2622     }
2623 
2624     XtFree(text.ptr);
2625     ctx->text.from_left = -1;
2626     ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
2627 				  XawstPositions, XawsdRight, text.length, True);
2628     EndAction(ctx);
2629 }
2630 
2631 /*
2632  * Selection Routines
2633  */
2634 static void
SelectWord(Widget w,XEvent * event,String * params,Cardinal * num_params)2635 SelectWord(Widget w, XEvent *event, String *params, Cardinal *num_params)
2636 {
2637     TextWidget ctx = (TextWidget)w;
2638     XawTextPosition l, r;
2639 
2640     StartAction(ctx, event);
2641     l = SrcScan(ctx->text.source, ctx->text.insertPos,
2642 		XawstWhiteSpace, XawsdLeft, 1, False);
2643     r = SrcScan(ctx->text.source, l, XawstWhiteSpace, XawsdRight, 1, False);
2644     _XawTextSetSelection(ctx, l, r, params, *num_params);
2645     EndAction(ctx);
2646 }
2647 
2648 static void
SelectAll(Widget w,XEvent * event,String * params,Cardinal * num_params)2649 SelectAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
2650 {
2651     TextWidget ctx = (TextWidget)w;
2652 
2653     StartAction(ctx, event);
2654     _XawTextSetSelection(ctx,zeroPosition,ctx->text.lastPos,params,*num_params);
2655     EndAction(ctx);
2656 }
2657 
2658 static void
ModifySelection(TextWidget ctx,XEvent * event,XawTextSelectionMode mode,XawTextSelectionAction action,String * params,Cardinal * num_params)2659 ModifySelection(TextWidget ctx, XEvent *event,
2660 		XawTextSelectionMode mode,
2661 		XawTextSelectionAction action,
2662 		String *params, Cardinal *num_params)
2663 {
2664 #ifndef OLDXAW
2665     int old_y = ctx->text.ev_y;
2666 #endif
2667 
2668     StartAction(ctx, event);
2669     NotePosition(ctx, event);
2670 
2671 #ifndef OLDXAW
2672     if (event->type == MotionNotify) {
2673 	if (ctx->text.ev_y <= ctx->text.margin.top) {
2674 	    if (old_y >= ctx->text.ev_y)
2675 		XawTextScroll(ctx, -1, 0);
2676 	}
2677 	else if (ctx->text.ev_y >= XtHeight(ctx) - ctx->text.margin.bottom) {
2678 	    if (old_y <= ctx->text.ev_y
2679 		&& !IsPositionVisible(ctx, ctx->text.lastPos))
2680 	      XawTextScroll(ctx, 1, 0);
2681 	}
2682     }
2683 #endif
2684     ctx->text.from_left = -1;
2685     _XawTextAlterSelection(ctx, mode, action, params, num_params);
2686 
2687     EndAction(ctx);
2688 }
2689 
2690 static void
SelectStart(Widget w,XEvent * event,String * params,Cardinal * num_params)2691 SelectStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
2692 {
2693     TextWidget ctx = (TextWidget)w;
2694 
2695 #ifndef OLDXAW
2696     if (!ctx->text.selection_state) {
2697 	ctx->text.selection_state = True;
2698 #endif
2699 	ModifySelection(ctx, event,
2700 			XawsmTextSelect, XawactionStart, params, num_params);
2701 #ifndef OLDXAW
2702     }
2703 #endif
2704 }
2705 
2706 static void
SelectAdjust(Widget w,XEvent * event,String * params,Cardinal * num_params)2707 SelectAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
2708 {
2709     TextWidget ctx = (TextWidget)w;
2710 
2711 #ifndef OLDXAW
2712     if (ctx->text.selection_state)
2713 #endif
2714 	ModifySelection(ctx, event,
2715 			XawsmTextSelect, XawactionAdjust, params, num_params);
2716 }
2717 
2718 static void
SelectEnd(Widget w,XEvent * event,String * params,Cardinal * num_params)2719 SelectEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
2720 {
2721     TextWidget ctx = (TextWidget)w;
2722 
2723 #ifndef OLDXAW
2724     if (ctx->text.selection_state) {
2725 	ctx->text.selection_state = False;
2726 #endif
2727 	ModifySelection(ctx, event,
2728 			XawsmTextSelect, XawactionEnd, params, num_params);
2729 #ifndef OLDXAW
2730     }
2731 #endif
2732 }
2733 
2734 static void
ExtendStart(Widget w,XEvent * event,String * params,Cardinal * num_params)2735 ExtendStart(Widget w, XEvent *event, String *params, Cardinal *num_params)
2736 {
2737     TextWidget ctx = (TextWidget)w;
2738 
2739 #ifndef OLDXAW
2740     if (!ctx->text.selection_state) {
2741 	ctx->text.selection_state = True;
2742 #endif
2743 	ModifySelection(ctx, event,
2744 			XawsmTextExtend, XawactionStart, params, num_params);
2745 #ifndef OLDXAW
2746     }
2747 #endif
2748 }
2749 
2750 static void
ExtendAdjust(Widget w,XEvent * event,String * params,Cardinal * num_params)2751 ExtendAdjust(Widget w, XEvent *event, String *params, Cardinal *num_params)
2752 {
2753     TextWidget ctx = (TextWidget)w;
2754 
2755 #ifndef OLDXAW
2756     if (ctx->text.selection_state)
2757 #endif
2758 	ModifySelection(ctx, event,
2759 			XawsmTextExtend, XawactionAdjust, params, num_params);
2760 }
2761 
2762 static void
ExtendEnd(Widget w,XEvent * event,String * params,Cardinal * num_params)2763 ExtendEnd(Widget w, XEvent *event, String *params, Cardinal *num_params)
2764 {
2765     TextWidget ctx = (TextWidget)w;
2766 
2767 #ifndef OLDXAW
2768     if (ctx->text.selection_state) {
2769 	ctx->text.selection_state = False;
2770 #endif
2771 	ModifySelection(ctx, event,
2772 			XawsmTextExtend, XawactionEnd, params, num_params);
2773 #ifndef OLDXAW
2774     }
2775 #endif
2776 }
2777 
2778 static void
SelectSave(Widget w,XEvent * event,String * params,Cardinal * num_params)2779 SelectSave(Widget  w, XEvent *event, String *params, Cardinal *num_params)
2780 {
2781     int num_atoms, n;
2782     Atom *sel;
2783     Display *dpy = XtDisplay(w);
2784     Atom selections[256];
2785 
2786     StartAction((TextWidget)w, event);
2787     num_atoms = (int)*num_params;
2788     if (num_atoms > 256)
2789 	num_atoms = 256;
2790     for (sel = selections, n = 0; n < num_atoms; n++, sel++, params++)
2791 	*sel = XInternAtom(dpy, *params, False);
2792     _XawTextSaltAwaySelection((TextWidget)w, selections, num_atoms);
2793     EndAction((TextWidget)w);
2794 }
2795 
2796 /*
2797  * Misc. Routines
2798  */
2799 /*ARGSUSED*/
2800 static void
SetKeyboardFocus(Widget w,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2801 SetKeyboardFocus(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2802 {
2803     Widget shell, parent;
2804 
2805     shell = parent = w;
2806     while (parent) {
2807 	if (XtIsShell(shell = parent))
2808 	    break;
2809 	parent = XtParent(parent);
2810     }
2811     XtSetKeyboardFocus(shell, w);
2812 }
2813 
2814 /*ARGSUSED*/
2815 static void
RedrawDisplay(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2816 RedrawDisplay(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2817 {
2818     StartAction((TextWidget)w, event);
2819     _XawTextClearAndCenterDisplay((TextWidget)w);
2820     EndAction((TextWidget)w);
2821 }
2822 
2823 /* This is kind of a hack, but, only one text widget can have focus at
2824  * a time on one display. There is a problem in the implementation of the
2825  * text widget, the scrollbars can not be adressed via editres, since they
2826  * are not children of a subclass of composite.
2827  * The focus variable is required to make sure only one text window will
2828  * show a block cursor at one time.
2829  */
2830 struct _focus { Display *display; Widget widget; };
2831 static struct _focus *focus;
2832 static Cardinal num_focus;
2833 
2834 /*ARGSUSED*/
2835 static void
DestroyFocusCallback(Widget w,XtPointer user_data,XtPointer call_data _X_UNUSED)2836 DestroyFocusCallback(Widget w, XtPointer user_data, XtPointer call_data _X_UNUSED)
2837 {
2838     struct _focus *f = (struct _focus*)(user_data);
2839 
2840     if (f->widget == w)
2841 	f->widget = NULL;
2842 }
2843 
2844 /*ARGSUSED*/
2845 static void
TextFocusIn(Widget w,XEvent * event,String * p,Cardinal * n)2846 TextFocusIn(Widget w, XEvent *event, String *p, Cardinal *n)
2847 {
2848     TextWidget ctx = (TextWidget)w;
2849     Bool display_caret = ctx->text.display_caret;
2850     int i;
2851 
2852     if (event->xfocus.detail == NotifyPointer)
2853 	return;
2854 
2855     if (event->xfocus.send_event) {
2856 	Window root, child;
2857 	int rootx, rooty, x, y;
2858 	unsigned int mask;
2859 
2860 	if (ctx->text.hasfocus)
2861 	    return;
2862 
2863 	if (XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
2864 			  &rootx, &rooty, &x, &y, &mask)) {
2865 	    if (child)
2866 		return;
2867 	}
2868     }
2869 
2870     /* Let the input method know focus has arrived. */
2871     _XawImSetFocusValues(w, NULL, 0);
2872 
2873     if (display_caret)
2874 	StartAction(ctx, event);
2875     ctx->text.hasfocus = TRUE;
2876     if (display_caret)
2877 	EndAction(ctx);
2878 
2879     for (i = 0; (Cardinal)i < num_focus; i++)
2880 	if (focus[i].display == XtDisplay(w))
2881 	    break;
2882     if ((Cardinal)i >= num_focus) {
2883 	focus = (struct _focus*)
2884 	    XtRealloc((XtPointer)focus, (Cardinal)(sizeof(struct _focus) * (num_focus + 1)));
2885 	i = (int)num_focus;
2886 	focus[i].widget = NULL;
2887 	focus[i].display = XtDisplay(w);
2888 	num_focus++;
2889     }
2890     if (focus[i].widget != w) {
2891 	Widget old = focus[i].widget;
2892 
2893 	focus[i].widget = w;
2894 	if (old != NULL) {
2895 	    TextFocusOut(old, event, p, n);
2896 	    /* TextFocusOut may set it to NULL */
2897 	    focus[i].widget = w;
2898 	}
2899 	XtAddCallback(w, XtNdestroyCallback,
2900 		      DestroyFocusCallback, (XtPointer)&focus[i]);
2901     }
2902 }
2903 
2904 /*ARGSUSED*/
2905 static void
TextFocusOut(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)2906 TextFocusOut(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
2907 {
2908     TextWidget ctx = (TextWidget)w;
2909     Bool display_caret = ctx->text.display_caret;
2910     Widget shell;
2911     Window window;
2912     int i, revert;
2913 
2914     shell = w;
2915     while (shell) {
2916 	if (XtIsShell(shell))
2917 	   break;
2918 	shell = XtParent(shell);
2919     }
2920 
2921     for (i = 0; (Cardinal)i < num_focus; i++)
2922 	if (focus[i].display == XtDisplay(w))
2923 	    break;
2924     XGetInputFocus(XtDisplay(w), &window, &revert);
2925     if ((XtWindow(shell) == window &&
2926 	 ((Cardinal)i < num_focus && focus[i].widget == w))
2927 	 || event->xfocus.detail == NotifyPointer)
2928 	return;
2929 
2930     if ((Cardinal)i < num_focus && focus[i].widget) {
2931 	XtRemoveCallback(focus[i].widget, XtNdestroyCallback,
2932 			 DestroyFocusCallback, (XtPointer)&focus[i]);
2933 	focus[i].widget = NULL;
2934     }
2935 
2936     /* Let the input method know focus has left.*/
2937     _XawImUnsetFocus(w);
2938 
2939     if (display_caret)
2940 	StartAction(ctx, event);
2941     ctx->text.hasfocus = FALSE;
2942     if (display_caret)
2943 	EndAction(ctx);
2944 }
2945 
2946 /*ARGSUSED*/
2947 static void
TextEnterWindow(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2948 TextEnterWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2949 {
2950     TextWidget ctx = (TextWidget)w;
2951 
2952     if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
2953 	&& !ctx->text.hasfocus)
2954 	_XawImSetFocusValues(w, NULL, 0);
2955 }
2956 
2957 /*ARGSUSED*/
2958 static void
TextLeaveWindow(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)2959 TextLeaveWindow(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2960 {
2961     TextWidget ctx = (TextWidget)w;
2962 
2963     if ((event->xcrossing.detail != NotifyInferior) && event->xcrossing.focus
2964 	&& !ctx->text.hasfocus)
2965 	_XawImUnsetFocus(w);
2966 }
2967 
2968 /*
2969  * Function:
2970  *	AutoFill
2971  *	Arguments: ctx - The text widget.
2972  *
2973  * Description:
2974  *	  Breaks the line at the previous word boundry when
2975  *	called inside InsertChar.
2976  */
2977 static void
AutoFill(TextWidget ctx)2978 AutoFill(TextWidget ctx)
2979 {
2980     int width, height, x, line_num, max_width;
2981     XawTextPosition ret_pos;
2982     XawTextBlock text;
2983     XRectangle cursor;
2984     wchar_t wc_buf[2];
2985 
2986     for (line_num = 0; line_num < ctx->text.lt.lines ; line_num++)
2987 	if (ctx->text.lt.info[line_num].position >= ctx->text.insertPos)
2988 	    break;
2989     if (line_num)
2990 	line_num--;		/* backup a line. */
2991 
2992     XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
2993     max_width = Max(0, (int)XtWidth(ctx) - RHMargins(ctx) - cursor.width);
2994 
2995     x = ctx->text.r_margin.left;
2996     XawTextSinkFindPosition(ctx->text.sink, ctx->text.lt.info[line_num].position,
2997 			    x, max_width, True, &ret_pos,
2998 			    &width, &height);
2999 
3000     if (ret_pos <= ctx->text.lt.info[line_num].position
3001 	|| ret_pos >= ctx->text.insertPos || ret_pos < 1)
3002 	return;
3003 
3004     XawTextSourceRead(ctx->text.source, ret_pos - 1, &text, 1);
3005 
3006     if (XawTextFormat(ctx, XawFmtWide)) {
3007 	wc_buf[0] = *(wchar_t *)text.ptr;
3008 	if (wc_buf[0] != _Xaw_atowc(XawSP) && wc_buf[0] != _Xaw_atowc(XawTAB))
3009 	    /* Only eats white spaces */
3010 	    return;
3011 
3012 	text.format = XawFmtWide;
3013 	text.ptr = (char *)wc_buf;
3014 	wc_buf[0] = _Xaw_atowc(XawLF);
3015 	wc_buf[1] = 0;
3016     }
3017     else {
3018 	if (text.ptr[0] != XawSP && text.ptr[0] != XawTAB)
3019 	    /* Only eats white spaces */
3020 	    return;
3021 
3022 	text.format = XawFmt8Bit;
3023 	text.ptr = "\n";
3024     }
3025     text.length = 1;
3026     text.firstPos = 0;
3027 
3028     if (_XawTextReplace(ctx, ret_pos - 1, ret_pos, &text))
3029 	XBell(XtDisplay((Widget)ctx), 0);
3030 
3031     if (++ctx->text.insertPos > ctx->text.lastPos)
3032 	ctx->text.insertPos = ctx->text.lastPos;
3033 }
3034 
3035 /*ARGSUSED*/
3036 static void
InsertChar(Widget w,XEvent * event,String * p _X_UNUSED,Cardinal * n _X_UNUSED)3037 InsertChar(Widget w, XEvent *event, String *p _X_UNUSED, Cardinal *n _X_UNUSED)
3038 {
3039     TextWidget ctx = (TextWidget)w;
3040     char *ptr, strbuf[128], ptrbuf[512];
3041     int count, error, mult = MULT(ctx);
3042     KeySym keysym;
3043     XawTextBlock text;
3044 #ifndef OLDXAW
3045     Bool format = False;
3046 #endif
3047     XawTextPosition from, to;
3048 
3049     if (XtIsSubclass (ctx->text.source, (WidgetClass) multiSrcObjectClass))
3050 	text.length = _XawImWcLookupString(w, &event->xkey, (wchar_t*)strbuf,
3051 					   sizeof(strbuf), &keysym);
3052     else
3053 	text.length = _XawLookupString(w, (XKeyEvent*)event, strbuf,
3054 				       sizeof(strbuf), &keysym);
3055 
3056     if (text.length == 0)
3057 	return;
3058 
3059     if (mult < 0) {
3060 	ctx->text.mult = 1;
3061 	return;
3062     }
3063 
3064     text.format = (unsigned long)_XawTextFormat(ctx);
3065     if (text.format == XawFmtWide) {
3066 	text.ptr = ptr = XawStackAlloc(sizeof(wchar_t) * (size_t)text.length
3067 				       * (size_t)mult, ptrbuf);
3068 	for (count = 0; count < mult; count++) {
3069 	    memcpy((char*)ptr, (char *)strbuf, sizeof(wchar_t) * (size_t)text.length);
3070 	    ptr += sizeof(wchar_t) * (size_t)text.length;
3071 	}
3072 #ifndef OLDXAW
3073 	if (mult == 1)
3074 	    format = ctx->text.left_column < ctx->text.right_column;
3075 #endif
3076     }
3077     else {	/* == XawFmt8Bit */
3078 	text.ptr = ptr = XawStackAlloc((unsigned)(text.length * mult), ptrbuf);
3079 	for (count = 0; count < mult; count++) {
3080 	    strncpy(ptr, strbuf, (size_t)text.length);
3081 	    ptr += text.length;
3082 	}
3083 #ifndef OLDXAW
3084 	if (mult == 1)
3085 	    format = ctx->text.left_column < ctx->text.right_column;
3086 #endif
3087     }
3088 
3089     text.length = text.length * mult;
3090     text.firstPos = 0;
3091 
3092     StartAction(ctx, event);
3093 #ifndef OLDXAW
3094     if (mult == 1)
3095 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3096 #endif
3097 
3098     from = ctx->text.insertPos;
3099 #ifndef OLDXAW
3100     if (ctx->text.overwrite) {
3101 	XawTextPosition tmp;
3102 
3103 	to = from + mult;
3104 	tmp = SrcScan(ctx->text.source, from, XawstEOL, XawsdRight, 1, False);
3105 	if (to > tmp)
3106 	    to = tmp;
3107     }
3108     else
3109 #endif
3110 	to = from;
3111 
3112     error = _XawTextReplace(ctx, from , to, &text);
3113 
3114     if (error == XawEditDone) {
3115 	ctx->text.from_left = -1;
3116 	ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
3117 				      XawstPositions, XawsdRight,
3118 				      text.length, True);
3119 	if (ctx->text.auto_fill) {
3120 #ifndef OLDXAW
3121 	    if (format)
3122 		(void)FormatText(ctx, SrcScan(ctx->text.source,
3123 					      ctx->text.insertPos, XawstEOL,
3124 					      XawsdLeft, 1, False), False,
3125 					      NULL, 0);
3126 	    else
3127 #endif
3128 		AutoFill(ctx);
3129 	}
3130     }
3131     else
3132 	XBell(XtDisplay(ctx), 50);
3133 
3134     XawStackFree(text.ptr, ptrbuf);
3135     EndAction(ctx);
3136 
3137     if (error == XawEditDone && text.format == XawFmt8Bit && text.length == 1
3138 	&& (text.ptr[0] == ')' || text.ptr[0] == ']' || text.ptr[0] == '}')
3139 	&& ctx->text.display_caret) {
3140 	static struct timeval tmval = {0, 500000};
3141 	fd_set fds;
3142 	Widget source = ctx->text.source;
3143 	XawTextPosition insertPos = ctx->text.insertPos, pos, tmp, last;
3144 	char left, right = text.ptr[0];
3145 	int level = 0;
3146 	XtAppContext app_context = XtWidgetToApplicationContext(w);
3147 
3148 	left = right == ')' ? '(' : right == ']' ? '[' : '{';
3149 
3150 	last = insertPos - 1;
3151 	do {
3152 	    text.ptr[0] = left;
3153 	    pos = XawTextSourceSearch(source, last, XawsdLeft, &text);
3154 	    if (pos == XawTextSearchError || !IsPositionVisible(ctx, pos))
3155 		return;
3156 	    text.ptr[0] = right;
3157 	    tmp = pos;
3158 	    do {
3159 		tmp = XawTextSourceSearch(source, tmp, XawsdRight, &text);
3160 		if (tmp == XawTextSearchError)
3161 		    return;
3162 		if (tmp <= last)
3163 		    ++level;
3164 	    } while (++tmp <= last);
3165 	    --level;
3166 	    last = pos;
3167 	} while (level);
3168 
3169 	StartAction(ctx, NULL);
3170 #ifndef OLDXAW
3171 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3172 #endif
3173 	ctx->text.insertPos = pos;
3174 	EndAction(ctx);
3175 
3176 	XSync(XtDisplay(w), False);
3177 	while (XtAppPending(app_context) & XtIMXEvent) {
3178 	    XEvent ev;
3179 	    if (! XtAppPeekEvent(app_context, &ev))
3180 		break;
3181 	    if (ev.type == KeyPress || ev.type == ButtonPress)
3182 		break;
3183 	    XtAppProcessEvent(app_context, XtIMXEvent);
3184 	}
3185 	FD_ZERO(&fds);
3186 	FD_SET(ConnectionNumber(XtDisplay(w)), &fds);
3187 	(void)select(FD_SETSIZE, &fds, NULL, NULL, &tmval);
3188 	if (tmval.tv_usec != 500000)
3189 	    usleep(40000);
3190 
3191 	StartAction(ctx, NULL);
3192 #ifndef OLDXAW
3193 	_XawSourceSetUndoMerge((TextSrcObject)ctx->text.source, True);
3194 #endif
3195 	ctx->text.insertPos = insertPos;
3196 	EndAction(ctx);
3197     }
3198 }
3199 
3200 /* IfHexConvertHexElseReturnParam() - called by InsertString
3201  *
3202  * i18n requires the ability to specify multiple characters in a hexa-
3203  * decimal string at once.  Since Insert was already too long, I made
3204  * this a seperate routine.
3205  *
3206  * A legal hex string in MBNF: '0' 'x' ( HEX-DIGIT HEX-DIGIT )+ '\0'
3207  *
3208  * WHEN:    the passed param is a legal hex string
3209  * RETURNS: a pointer to that converted, null terminated hex string;
3210  *	    len_return holds the character count of conversion result
3211  *
3212  * WHEN:    the passed param is not a legal hex string:
3213  * RETURNS: the parameter passed;
3214  *	    len_return holds the char count of param.
3215  *
3216  * NOTE:    In neither case will there be strings to free. */
3217 static char *
IfHexConvertHexElseReturnParam(char * param,int * len_return)3218 IfHexConvertHexElseReturnParam(char *param, int *len_return)
3219 {
3220     char *p;		/* steps through param char by char */
3221     char c;		/* holds the character pointed to by p */
3222     int ind;		/* steps through hexval buffer char by char */
3223     static char hexval[XawTextActionMaxHexChars];
3224     Boolean first_digit;
3225 
3226     /* reject if it doesn't begin with 0x and at least one more character. */
3227     if ((param[0] != '0') || (param[1] != 'x') || (param[2] == '\0')) {
3228 	*len_return = (int)strlen(param);
3229 	return(param);
3230     }
3231 
3232     /* Skip the 0x; go character by character shifting and adding. */
3233     first_digit = True;
3234     ind = 0;
3235     hexval[ind] = '\0';
3236 
3237     for (p = param+2; (c = *p) != '\0'; p++) {
3238 	hexval[ind] = (char)(hexval[ind] * 16);
3239 	if (c >= '0' && c <= '9')
3240 	    hexval[ind] = (char)(hexval[ind] + (c - '0'));
3241 	else if (c >= 'a' && c <= 'f')
3242 	    hexval[ind] = (char)(hexval[ind] + (c - 'a' + 10));
3243 	else if (c >= 'A' && c <= 'F')
3244 	    hexval[ind] = (char)(hexval[ind] + (c - 'A' + 10));
3245 	else
3246 	    break;
3247 
3248 	/* If we didn't break in preceding line, it was a good hex char. */
3249 	if (first_digit)
3250 	    first_digit = False;
3251 	else {
3252 	    first_digit = True;
3253 	    if (++ind < XawTextActionMaxHexChars)
3254 		hexval[ind] = '\0';
3255 	    else {
3256 		*len_return = (int)strlen(param);
3257 		return(param);
3258 	    }
3259 	}
3260     }
3261 
3262     /* We quit the above loop becasue we hit a non hex.  If that char is \0... */
3263     if ((c == '\0') && first_digit) {
3264 	*len_return = (int)strlen(hexval);
3265 	return (hexval);       /* ...it was a legal hex string, so return it */
3266     }
3267 
3268     /* Else, there were non-hex chars or odd digit count, so... */
3269 
3270     *len_return = (int)strlen(param);
3271     return (param);			   /* ...return the verbatim string. */
3272 }
3273 
3274 /* InsertString() - action
3275  *
3276  * Mostly rewritten for R6 i18n.
3277  *
3278  * Each parameter, in turn, will be insert at the inputPos
3279  * and the inputPos advances to the insertion's end.
3280  *
3281  * The exception is that parameters composed of the two
3282  * characters 0x, followed only by an even number of
3283  * hexadecimal digits will be converted to characters */
3284 /*ARGSUSED*/
3285 static void
InsertString(Widget w,XEvent * event,String * params,Cardinal * num_params)3286 InsertString(Widget w, XEvent *event, String *params, Cardinal *num_params)
3287 {
3288     TextWidget ctx = (TextWidget)w;
3289     XtAppContext app_con = XtWidgetToApplicationContext(w);
3290     XawTextBlock text;
3291     int i;
3292 
3293     text.firstPos = 0;
3294     text.format = (unsigned long)_XawTextFormat(ctx);
3295 
3296     StartAction(ctx, event);
3297     for (i = (int)*num_params; i; i--, params++) {	/* DO FOR EACH PARAMETER */
3298 	text.ptr = IfHexConvertHexElseReturnParam(*params, &text.length);
3299 
3300 	if (text.length == 0)
3301 	    continue;
3302 
3303 	if (XawTextFormat(ctx, XawFmtWide)) {	/* convert to WC */
3304 	    int temp_len;
3305 
3306 	    text.ptr = (char*)_XawTextMBToWC(XtDisplay(w), text.ptr,
3307 					     &text.length);
3308 
3309 	    if (text.ptr == NULL) {	  /* conversion error */
3310 		XtAppWarningMsg(app_con,
3311 				"insertString", "textAction", "XawError",
3312 				"insert-string()'s parameter contents "
3313 				"not legal in this locale.",
3314 				NULL, NULL);
3315 		ParameterError(w, *params);
3316 		continue;
3317 	   }
3318 
3319 	    /* Double check that the new input is legal: try to convert to MB. */
3320 
3321 	    temp_len = text.length;	 /* _XawTextWCToMB's 3rd arg is in_out */
3322 	    if (_XawTextWCToMB(XtDisplay(w), (wchar_t*)text.ptr, &temp_len)
3323 		== NULL) {
3324 		XtAppWarningMsg( app_con,
3325 				 "insertString", "textAction", "XawError",
3326 				 "insert-string()'s parameter contents "
3327 				 "not legal in this locale.",
3328 				 NULL, NULL);
3329 		ParameterError(w, *params);
3330 		continue;
3331 	    }
3332 	} /* convert to WC */
3333 
3334 	if (_XawTextReplace(ctx, ctx->text.insertPos,
3335 			    ctx->text.insertPos, &text)) {
3336 	    XBell(XtDisplay(ctx), 50);
3337 	    EndAction(ctx);
3338 	    return;
3339 	}
3340 
3341 	ctx->text.from_left = -1;
3342 	/* Advance insertPos to the end of the string we just inserted. */
3343 	ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.old_insert,
3344 				       XawstPositions, XawsdRight, text.length,
3345 				      True);
3346 
3347     } /* DO FOR EACH PARAMETER */
3348 
3349     EndAction(ctx);
3350 }
3351 
3352 /* DisplayCaret() - action
3353  *
3354  * The parameter list should contain one boolean value.  If the
3355  * argument is true, the cursor will be displayed.  If false, not.
3356  *
3357  * The exception is that EnterNotify and LeaveNotify events may
3358  * have a second argument, "always".  If they do not, the cursor
3359  * is only affected if the focus member of the event is true.	*/
3360 static void
DisplayCaret(Widget w,XEvent * event,String * params,Cardinal * num_params)3361 DisplayCaret(Widget w, XEvent *event, String *params, Cardinal *num_params)
3362 {
3363     TextWidget ctx = (TextWidget)w;
3364     Bool display_caret = True;
3365 
3366     if	((event->type == EnterNotify || event->type == LeaveNotify)
3367 	 && ((*num_params >= 2) && (strcmp(params[1], "always") == 0))
3368 	 && (!event->xcrossing.focus))
3369 	return;
3370 
3371     if (*num_params > 0) {	/* default arg is "True" */
3372 	XrmValue from, to;
3373 	from.size = (unsigned)strlen(from.addr = params[0]);
3374 	XtConvert(w, XtRString, &from, XtRBoolean, &to);
3375 
3376 	if (to.addr != NULL)
3377 	    display_caret = *(Boolean*)to.addr;
3378 	if (ctx->text.display_caret == display_caret)
3379 	    return;
3380     }
3381     StartAction(ctx, event);
3382     ctx->text.display_caret = (Boolean)display_caret;
3383     EndAction(ctx);
3384 }
3385 
3386 #ifndef OLDXAW
3387 static void
Numeric(Widget w,XEvent * event,String * params,Cardinal * num_params)3388 Numeric(Widget w, XEvent *event, String *params, Cardinal *num_params)
3389 {
3390     TextWidget ctx = (TextWidget)w;
3391 
3392     if (ctx->text.numeric) {
3393 	long mult = ctx->text.mult;
3394 
3395 	if (*num_params != 1 || strlen(params[0]) != 1
3396 	    || (!isdigit(params[0][0])
3397 		&& (params[0][0] != '-' || mult != 0))) {
3398 	    char err_buf[256];
3399 
3400 	    if (event && (event->type == KeyPress || event->type == KeyRelease)
3401 		&& params[0][0] == '-') {
3402 		InsertChar(w, event, params, num_params);
3403 		return;
3404 	    }
3405 	    snprintf(err_buf, sizeof(err_buf),
3406 		     "numeric: Invalid argument%s'%s'",
3407 		     *num_params ? ", " : "",
3408 		     *num_params ? params[0] : "");
3409 	    XtAppWarning(XtWidgetToApplicationContext(w), err_buf);
3410 	    ctx->text.numeric = False;
3411 	    ctx->text.mult = 1;
3412 	    return;
3413 	}
3414 	if (params[0][0] == '-') {
3415 	    ctx->text.mult = 32767;
3416 	    return;
3417 	}
3418 	else if (mult == 32767) {
3419 	    mult = ctx->text.mult = (short)(- (params[0][0] - '0'));
3420 	    return;
3421 	}
3422 	else {
3423 	    mult = mult * 10 + (params[0][0] - '0') * (mult < 0 ? -1 : 1);
3424 	    ctx->text.mult = (short)(ctx->text.mult * 10 + (params[0][0] - '0') *
3425 			     (mult < 0 ? -1 : 1));
3426 	}
3427 	if (mult != ctx->text.mult || mult >= 32767) {	/* checks for overflow */
3428 	    XBell(XtDisplay(w), 0);
3429 	    ctx->text.mult = 1;
3430 	    ctx->text.numeric = False;
3431 	    return;
3432 	}
3433     }
3434     else
3435 	InsertChar(w, event, params, num_params);
3436 }
3437 
3438 /*ARGSUSED*/
3439 static void
KeyboardReset(Widget w,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)3440 KeyboardReset(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
3441 {
3442     TextWidget ctx = (TextWidget)w;
3443 
3444     ctx->text.numeric = False;
3445     ctx->text.mult = 1;
3446 
3447     (void)_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
3448 
3449     if (ctx->text.kill_ring_ptr) {
3450 	--ctx->text.kill_ring_ptr->refcount;
3451 	ctx->text.kill_ring_ptr = NULL;
3452     }
3453     ctx->text.kill_ring = 0;
3454 
3455     XBell(XtDisplay(w), 0);
3456 }
3457 #endif /* OLDXAW */
3458 
3459 /* Multiply() - action
3460  *
3461  * The parameter list may contain either a number or the string 'Reset'.
3462  *
3463  * A number will multiply the current multiplication factor by that number.
3464  * Many of the text widget actions will will perform n actions, where n is
3465  * the multiplication factor.
3466  *
3467  * The string reset will reset the mutiplication factor to 1. */
3468 /*ARGSUSED*/
3469 static void
Multiply(Widget w,XEvent * event _X_UNUSED,String * params,Cardinal * num_params)3470 Multiply(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
3471 {
3472     TextWidget ctx = (TextWidget)w;
3473     int mult;
3474 
3475     if (*num_params != 1) {
3476 	XtAppError(XtWidgetToApplicationContext(w),
3477 		   "Xaw Text Widget: multiply() takes exactly one argument.");
3478 	XBell(XtDisplay(w), 0);
3479 	return;
3480     }
3481 
3482     if ((params[0][0] == 'r') || (params[0][0] == 'R')) {
3483 	XBell(XtDisplay(w), 0);
3484 #ifndef OLDXAW
3485 	ctx->text.numeric = False;
3486 #endif
3487 	ctx->text.mult = 1;
3488 	return;
3489     }
3490 
3491 #ifndef OLDXAW
3492     if (params[0][0] == 's' || params[0][0] == 'S') {
3493 	ctx->text.numeric = True;
3494 	ctx->text.mult = 0;
3495 	return;
3496     }
3497     else
3498 #endif
3499 	if ((mult = atoi(params[0])) == 0) {
3500 	char buf[BUFSIZ];
3501 
3502 	snprintf(buf, sizeof(buf),
3503 		 "Xaw Text Widget: multiply() argument "
3504 		 "must be a number greater than zero, or 'Reset'.");
3505 	XtAppError(XtWidgetToApplicationContext(w), buf);
3506 	XBell(XtDisplay(w), 50);
3507 	return;
3508     }
3509 
3510     ctx->text.mult = (short)(ctx->text.mult * mult);
3511 }
3512 
3513 /* StripOutOldCRs() - called from FormRegion
3514  *
3515  * removes CRs in widget ctx, from from to to.
3516  *
3517  * RETURNS: the new ending location (we may add some characters),
3518  * or XawReplaceError if the widget can't be written to. */
3519 static XawTextPosition
StripOutOldCRs(TextWidget ctx,XawTextPosition from,XawTextPosition to,XawTextPosition * pos,int num_pos)3520 StripOutOldCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3521 	       XawTextPosition *pos, int num_pos)
3522 {
3523     XawTextPosition startPos, endPos, eop_begin, eop_end, temp;
3524     Widget src = ctx->text.source;
3525     XawTextBlock text;
3526     char *buf;
3527     static wchar_t wc_two_spaces[3];
3528     int idx;
3529 
3530     /* Initialize our TextBlock with two spaces. */
3531     text.firstPos = 0;
3532     text.format = (unsigned long)_XawTextFormat(ctx);
3533     if (text.format == XawFmt8Bit)
3534       text.ptr= "  ";
3535     else {
3536 	wc_two_spaces[0] = _Xaw_atowc(XawSP);
3537 	wc_two_spaces[1] = _Xaw_atowc(XawSP);
3538 	wc_two_spaces[2] = 0;
3539 	text.ptr = (char*)wc_two_spaces;
3540     }
3541 
3542     /* Strip out CR's. */
3543     eop_begin = eop_end = startPos = endPos = from;
3544 
3545     /* CONSTCOND */
3546     while (TRUE) {
3547 	endPos=SrcScan(src, startPos, XawstEOL, XawsdRight, 1, False);
3548 
3549 	temp = SrcScan(src, endPos, XawstWhiteSpace, XawsdLeft, 1, False);
3550 	temp = SrcScan(src, temp,   XawstWhiteSpace, XawsdRight,1, False);
3551 
3552 	if (temp > startPos)
3553 	    endPos = temp;
3554 
3555 	if (endPos >= to)
3556 	    break;
3557 
3558 	if (endPos >= eop_begin) {
3559 	    startPos = eop_end;
3560 	    eop_begin=SrcScan(src, startPos, XawstParagraph,
3561 			      XawsdRight, 1,False);
3562 	    eop_end = SrcScan(src, startPos, XawstParagraph,
3563 			      XawsdRight, 1, True);
3564 	}
3565 	else {
3566 	    XawTextPosition periodPos, next_word;
3567 	    int i, len;
3568 
3569 	    periodPos = SrcScan(src, endPos, XawstPositions,
3570 				XawsdLeft, 1, True);
3571 	    next_word = SrcScan(src, endPos, XawstWhiteSpace,
3572 				XawsdRight, 1, False);
3573 
3574 	    len = (int)(next_word - periodPos);
3575 
3576 	    text.length = 1;
3577 	    buf = _XawTextGetText(ctx, periodPos, next_word);
3578 	    if (text.format == XawFmtWide) {
3579 		if (periodPos < endPos && ((wchar_t*)buf)[0] == _Xaw_atowc('.'))
3580 		  text.length++;
3581 	    }
3582 	    else
3583 		if (periodPos < endPos && buf[0] == '.')
3584 		    text.length++;	  /* Put in two spaces. */
3585 
3586 	    /*
3587 	     * Remove all extra spaces.
3588 	     */
3589 	    for (i = 1 ; i < len; i++)
3590 		if (text.format ==  XawFmtWide) {
3591 		    if (!iswspace(((wchar_t*)buf)[i]) || ((periodPos + i) >= to))
3592 			break;
3593 		}
3594 		else if (!isspace(buf[i]) || (periodPos + i) >= to)
3595 		    break;
3596 
3597 	    XtFree(buf);
3598 
3599 	    to -= (i - text.length - 1);
3600 	    startPos = SrcScan(src, periodPos, XawstPositions,
3601 			       XawsdRight, i, True);
3602 	    if (_XawTextReplace(ctx, endPos, startPos, &text) != XawEditDone)
3603 		return (XawReplaceError);
3604 
3605 	    for (idx = 0; idx < num_pos; idx++) {
3606 		if (endPos < pos[idx]) {
3607 		    if (startPos < pos[idx])
3608 			pos[idx] -= startPos - endPos;
3609 		    else
3610 			pos[idx] = endPos;
3611 		    pos[idx] += text.length;
3612 		}
3613 	    }
3614 
3615 	    startPos -= i - text.length;
3616 	}
3617     }
3618 
3619     return (to);
3620 }
3621 
3622 /* InsertNewCRs() - called from FormRegion
3623  *
3624  * inserts new CRs for FormRegion, thus for FormParagraph action */
3625 static void
InsertNewCRs(TextWidget ctx,XawTextPosition from,XawTextPosition to,XawTextPosition * pos,int num_pos)3626 InsertNewCRs(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3627 	     XawTextPosition *pos, int num_pos)
3628 {
3629     XawTextPosition startPos, endPos, space, eol;
3630     XawTextBlock text;
3631     int i, width, height, len, wwidth, idx;
3632     char *buf;
3633     static wchar_t wide_CR[2];
3634 
3635     text.firstPos = 0;
3636     text.length = 1;
3637     text.format = (unsigned long)_XawTextFormat(ctx);
3638 
3639     if (text.format == XawFmt8Bit)
3640 	text.ptr = "\n";
3641     else {
3642 	wide_CR[0] = _Xaw_atowc(XawLF);
3643 	wide_CR[1] = 0;
3644 	text.ptr = (char*)wide_CR;
3645     }
3646 
3647     startPos = from;
3648 
3649     wwidth = (int)XtWidth(ctx) - (int)HMargins(ctx);
3650     if (ctx->text.wrap != XawtextWrapNever) {
3651 	XRectangle cursor;
3652 
3653 	XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
3654 	wwidth -= (int)cursor.width;
3655     }
3656     wwidth = XawMax(0, wwidth);
3657 
3658     /* CONSTCOND */
3659     while (TRUE) {
3660 	XawTextSinkFindPosition(ctx->text.sink, startPos,
3661 				(int)ctx->text.r_margin.left, wwidth,
3662 				True, &eol, &width, &height);
3663 	if (eol == startPos)
3664 	    ++eol;
3665 	if (eol >= to)
3666 	    break;
3667 
3668 	eol = SrcScan(ctx->text.source, eol, XawstPositions,
3669 		      XawsdLeft, 1, True);
3670 	space = SrcScan(ctx->text.source, eol, XawstWhiteSpace,
3671 			XawsdRight,1, True);
3672 
3673 	startPos = endPos = eol;
3674 	if (eol == space)
3675 	    return;
3676 
3677 	len = (int)(space - eol);
3678 	buf = _XawTextGetText(ctx, eol, space);
3679 	for (i = 0 ; i < len ; i++)
3680 	    if (text.format == XawFmtWide) {
3681 		if (!iswspace(((wchar_t*)buf)[i]))
3682 		    break;
3683 	    }
3684 	    else if (!isspace(buf[i]))
3685 		break;
3686 
3687 	to -= (i - 1);
3688 	endPos = SrcScan(ctx->text.source, endPos,
3689 			 XawstPositions, XawsdRight, i, True);
3690 	XtFree(buf);
3691 
3692 	if (_XawTextReplace(ctx, startPos, endPos, &text))
3693 	    return;
3694 
3695 	for (idx = 0; idx < num_pos; idx++) {
3696 	    if (startPos < pos[idx]) {
3697 		if (endPos < pos[idx])
3698 		    pos[idx] -= endPos - startPos;
3699 		else
3700 		    pos[idx] = startPos;
3701 		pos[idx] += text.length;
3702 	    }
3703 	}
3704 
3705 	startPos = SrcScan(ctx->text.source, startPos,
3706 			   XawstPositions, XawsdRight, 1, True);
3707     }
3708 }
3709 
3710 /* FormRegion() - called by FormParagraph
3711  *
3712  * oversees the work of paragraph-forming a region
3713  *
3714  * Return:
3715  *	XawEditDone if successful, or XawReplaceError
3716  */
3717 static int
FormRegion(TextWidget ctx,XawTextPosition from,XawTextPosition to,XawTextPosition * pos,int num_pos)3718 FormRegion(TextWidget ctx, XawTextPosition from, XawTextPosition to,
3719 	   XawTextPosition *pos, int num_pos)
3720 {
3721 #ifndef OLDXAW
3722     Bool format = ctx->text.auto_fill
3723 	&& ctx->text.left_column < ctx->text.right_column;
3724 #endif
3725 
3726     if (from >= to)
3727 	return (XawEditDone);
3728 
3729 #ifndef OLDXAW
3730     if (format) {
3731 	XawTextPosition len = ctx->text.lastPos;
3732 	int inc = 0;
3733 
3734 	if (ctx->text.justify == XawjustifyLeft ||
3735 	    ctx->text.justify == XawjustifyFull) {
3736 	    Untabify(ctx, from, to, pos, num_pos, NULL);
3737 	    to += ctx->text.lastPos - len;
3738 	    len = ctx->text.insertPos;
3739 	    (void)BlankLine((Widget)ctx, from, &inc);
3740 	    if (from + inc >= to)
3741 		return (XawEditDone);
3742 	}
3743 	if (!StripSpaces(ctx, from + inc, to, pos, num_pos, NULL))
3744 	    return (XawReplaceError);
3745 	to += ctx->text.lastPos - len;
3746 
3747 	FormatText(ctx, from, ctx->text.justify != XawjustifyFull, pos, num_pos);
3748     }
3749     else {
3750 #endif
3751 	if ((to = StripOutOldCRs(ctx, from, to, pos, num_pos)) == XawReplaceError)
3752 	    return (XawReplaceError);
3753 	InsertNewCRs(ctx, from, to, pos, num_pos);
3754 #ifndef OLDXAW
3755     }
3756 #endif
3757     ctx->text.from_left = -1;
3758 
3759     return (XawEditDone);
3760 }
3761 
3762 #ifndef OLDXAW
3763 static Bool
BlankLine(Widget w,XawTextPosition pos,int * blanks_return)3764 BlankLine(Widget w, XawTextPosition pos, int *blanks_return)
3765 {
3766     int i, blanks = 0;
3767     XawTextBlock block;
3768     Widget src = XawTextGetSource(w);
3769     XawTextPosition l = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, False);
3770     XawTextPosition r = SrcScan(src, pos, XawstEOL, XawsdRight, 1, False);
3771 
3772     while (l < r) {
3773 	l = XawTextSourceRead(src, l, &block, (int)(r - l));
3774 	if (block.length == 0) {
3775 	    if (blanks_return)
3776 		*blanks_return = blanks;
3777 	    return (True);
3778 	}
3779 	if (XawTextFormat((TextWidget)w, XawFmt8Bit)) {
3780 	    for (i = 0; i < block.length; i++, blanks++)
3781 		if (block.ptr[i] != ' ' &&
3782 		    block.ptr[i] != '\t') {
3783 		    if (blanks_return)
3784 			*blanks_return = blanks;
3785 		    return (block.ptr[i] == '\n');
3786 		}
3787 	}
3788 	else if (XawTextFormat((TextWidget)w, XawFmtWide)) {
3789 	    for (i = 0; i < block.length; i++, blanks++)
3790 		if (_Xaw_atowc(XawSP) != ((wchar_t*)block.ptr)[i] &&
3791 		    _Xaw_atowc(XawTAB) != ((wchar_t*)block.ptr)[i]) {
3792 		    if (blanks_return)
3793 			*blanks_return = blanks;
3794 		    return (_Xaw_atowc(XawLF) == ((wchar_t*)block.ptr)[i]);
3795 		}
3796 	}
3797     }
3798 
3799     return (True);
3800 }
3801 
3802 static Bool
GetBlockBoundaries(TextWidget ctx,XawTextPosition * from_return,XawTextPosition * to_return)3803 GetBlockBoundaries(TextWidget ctx,
3804 		   XawTextPosition *from_return, XawTextPosition *to_return)
3805 {
3806     XawTextPosition from, to;
3807 
3808     if (ctx->text.auto_fill && ctx->text.left_column < ctx->text.right_column) {
3809 	if (ctx->text.s.left != ctx->text.s.right) {
3810 	    from = SrcScan(ctx->text.source,
3811 			   XawMin(ctx->text.s.left, ctx->text.s.right),
3812 			   XawstEOL, XawsdLeft, 1, False);
3813 	    to   = SrcScan(ctx->text.source,
3814 			   XawMax(ctx->text.s.right, ctx->text.s.right),
3815 			   XawstEOL, XawsdRight, 1, False);
3816 	}
3817 	else {
3818 	    XawTextBlock block;
3819 	    XawTextPosition tmp;
3820 	    Bool first;
3821 
3822 	    from = to = ctx->text.insertPos;
3823 
3824 	    /* find from position */
3825 	    first = True;
3826 	    while (1) {
3827 		tmp = from;
3828 		from = SrcScan(ctx->text.source, from, XawstEOL, XawsdLeft,
3829 			       1 + !first, False);
3830 		XawTextSourceRead(ctx->text.source, from, &block, 1);
3831 		if (block.length == 0 ||
3832 		    (XawTextFormat(ctx, XawFmt8Bit) &&
3833 		     block.ptr[0] != ' ' &&
3834 		     block.ptr[0] != '\t' &&
3835 		     !isalnum(*(unsigned char*)block.ptr)) ||
3836 		    (XawTextFormat(ctx, XawFmtWide) &&
3837 		     _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
3838 		     _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
3839 		     !iswalnum((wint_t)*(wchar_t*)block.ptr)) ||
3840 		    BlankLine((Widget)ctx, from, NULL)) {
3841 		    from = tmp;
3842 		    break;
3843 		}
3844 		if (from == tmp && !first)
3845 		    break;
3846 		first = False;
3847 	    }
3848 	    if (first)
3849 		return (False);
3850 
3851 	    /* find to position */
3852 	    first = True;
3853 	    while (1) {
3854 		tmp = to;
3855 		to = SrcScan(ctx->text.source, to, XawstEOL, XawsdRight,
3856 			     1 + !first, False);
3857 		XawTextSourceRead(ctx->text.source, to + (to < ctx->text.lastPos),
3858 				  &block, 1);
3859 		if (block.length == 0 ||
3860 		    (XawTextFormat(ctx, XawFmt8Bit) &&
3861 		     block.ptr[0] != ' ' &&
3862 		     block.ptr[0] != '\t' &&
3863 		     !isalnum(*(unsigned char*)block.ptr)) ||
3864 		    (XawTextFormat(ctx, XawFmtWide) &&
3865 		     _Xaw_atowc(XawSP) != *(wchar_t*)block.ptr &&
3866 		     _Xaw_atowc(XawTAB) != *(wchar_t*)block.ptr &&
3867 		     !iswalnum((wint_t)*(wchar_t*)block.ptr)) ||
3868 		    BlankLine((Widget)ctx, to, NULL))
3869 		    break;
3870 		if (to == tmp && !first)
3871 		    break;
3872 		first = False;
3873 	    }
3874 	}
3875     }
3876     else {
3877 	from = SrcScan(ctx->text.source, ctx->text.insertPos, XawstEOL,
3878 		       XawsdLeft, 1, False);
3879 	if (BlankLine((Widget)ctx, from, NULL))
3880 	    return (False);
3881 	from = SrcScan(ctx->text.source, from, XawstParagraph,
3882 		       XawsdLeft, 1, False);
3883 	if (BlankLine((Widget)ctx, from, NULL))
3884 	    from = SrcScan(ctx->text.source, from, XawstEOL,
3885 			   XawsdRight, 1, True);
3886 	to = SrcScan(ctx->text.source, from, XawstParagraph,
3887 			XawsdRight, 1, False);
3888     }
3889 
3890     if (from < to) {
3891 	*from_return = from;
3892 	*to_return = to;
3893 	return (True);
3894     }
3895 
3896     return (False);
3897 }
3898 #endif /* OLDXAW */
3899 
3900 /* FormParagraph() - action
3901  *
3902  * removes and reinserts CRs to maximize line length without clipping */
3903 /*ARGSUSED*/
3904 static void
FormParagraph(Widget w,XEvent * event,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)3905 FormParagraph(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
3906 {
3907     TextWidget ctx = (TextWidget)w;
3908     XawTextPosition from, to, buf[32], *pos;
3909 #ifndef OLDXAW
3910     XawTextPosition endPos = 0;
3911     char *lbuf = NULL, *rbuf;
3912     TextSrcObject src = (TextSrcObject)ctx->text.source;
3913     Cardinal i;
3914     Bool undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
3915 #endif
3916 
3917     StartAction(ctx, event);
3918 
3919 #ifndef OLDXAW
3920     pos = XawStackAlloc(sizeof(XawTextPosition) * src->textSrc.num_text, buf);
3921     for (i = 0; i < src->textSrc.num_text; i++)
3922 	pos[i] = ((TextWidget)src->textSrc.text[i])->text.old_insert;
3923 #else
3924     pos = buf;
3925     *pos = ctx->text.old_insert;
3926 #endif
3927 
3928 #ifndef OLDXAW
3929     if (!GetBlockBoundaries(ctx, &from, &to)) {
3930 	EndAction(ctx);
3931 	XawStackFree(pos, buf);
3932 	return;
3933     }
3934 
3935     if (undo) {
3936 	src->textSrc.undo_state = True;
3937 	lbuf = _XawTextGetText(ctx, from, to);
3938 	endPos = ctx->text.lastPos;
3939     }
3940 
3941     if (FormRegion(ctx, from, to, pos, (int)src->textSrc.num_text) == XawReplaceError) {
3942 	XawStackFree(pos, buf);
3943 	pos = buf;
3944 #else
3945     from =  SrcScan(ctx->text.source, ctx->text.insertPos,
3946 		    XawstParagraph, XawsdLeft, 1, False);
3947     to  =   SrcScan(ctx->text.source, from,
3948 		    XawstParagraph, XawsdRight, 1, False);
3949 
3950     if (FormRegion(ctx, from, to, pos, 1) == XawReplaceError) {
3951 #endif
3952 	XBell(XtDisplay(w), 0);
3953 #ifndef OLDXAW
3954 	if (undo) {
3955 	    src->textSrc.undo_state = False;
3956 	    XtFree(lbuf);
3957 	}
3958 #endif
3959     }
3960 #ifndef OLDXAW
3961     else if (undo) {
3962 	/* makes the form-paragraph only one undo/redo step */
3963 	unsigned llen, rlen, size;
3964 	XawTextBlock block;
3965 
3966 	llen = (unsigned)(to - from);
3967 	rlen = (unsigned)(llen + (ctx->text.lastPos - endPos));
3968 
3969 	block.firstPos = 0;
3970 	block.format = (unsigned long)_XawTextFormat(ctx);
3971 
3972 	rbuf = _XawTextGetText(ctx, from, from + rlen);
3973 
3974 	size = XawTextFormat(ctx, XawFmtWide) ? sizeof(wchar_t) : sizeof(char);
3975 	if (llen != rlen || memcmp(lbuf, rbuf, llen * size)) {
3976 	    block.ptr = lbuf;
3977 	    block.length = (int)llen;
3978 	    _XawTextReplace(ctx, from, from + rlen, &block);
3979 
3980 	    src->textSrc.undo_state = False;
3981 	    block.ptr = rbuf;
3982 	    block.length = (int)rlen;
3983 	    _XawTextReplace(ctx, from, from + llen, &block);
3984 	}
3985 	else
3986 	    src->textSrc.undo_state = False;
3987 	XtFree(lbuf);
3988 	XtFree(rbuf);
3989     }
3990 
3991     for (i = 0; i < src->textSrc.num_text; i++) {
3992 	TextWidget tw = (TextWidget)src->textSrc.text[i];
3993 
3994 	tw->text.old_insert = tw->text.insertPos = pos[i];
3995 	_XawTextBuildLineTable(tw, SrcScan((Widget)src, tw->text.lt.top, XawstEOL,
3996 			       XawsdLeft, 1, False), False);
3997 	tw->text.clear_to_eol = True;
3998     }
3999     XawStackFree(pos, buf);
4000 #else
4001     ctx->text.old_insert = ctx->text.insertPos = *pos;
4002     _XawTextBuildLineTable(ctx, SrcScan(ctx->text.source, ctx->text.lt.top,
4003 			   XawstEOL, XawsdLeft, 1, False), False);
4004     ctx->text.clear_to_eol = True;
4005 #endif
4006     ctx->text.showposition = True;
4007 
4008     EndAction(ctx);
4009 }
4010 
4011 /* TransposeCharacters() - action
4012  *
4013  * Swaps the character to the left of the mark
4014  * with the character to the right of the mark */
4015 /*ARGSUSED*/
4016 static void
4017 TransposeCharacters(Widget w, XEvent *event,
4018 		    String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4019 {
4020     TextWidget ctx = (TextWidget)w;
4021     XawTextPosition start, end;
4022     XawTextBlock text;
4023     char *buf;
4024     int i, mult = MULT(ctx);
4025 
4026     if (mult < 0) {
4027 	ctx->text.mult = 1;
4028 	return;
4029     }
4030 
4031     StartAction(ctx, event);
4032 
4033     /* Get bounds. */
4034 
4035     start = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
4036 		    XawsdLeft, 1, True);
4037     end = SrcScan(ctx->text.source, ctx->text.insertPos, XawstPositions,
4038 		  XawsdRight, mult, True);
4039 
4040     /* Make sure we aren't at the very beginning or end of the buffer. */
4041 
4042     if (start == ctx->text.insertPos || end == ctx->text.insertPos) {
4043 	XBell(XtDisplay(w), 0);   /* complain. */
4044 	EndAction(ctx);
4045 	return;
4046     }
4047 
4048     ctx->text.from_left = -1;
4049     ctx->text.insertPos = end;
4050 
4051     text.firstPos = 0;
4052     text.format = (unsigned long)_XawTextFormat(ctx);
4053 
4054     /* Retrieve text and swap the characters. */
4055     if (text.format == XawFmtWide) {
4056 	wchar_t wc;
4057 	wchar_t *wbuf;
4058 
4059 	wbuf = (wchar_t*)_XawTextGetText(ctx, start, end);
4060 	text.length = (int)wcslen(wbuf);
4061 	wc = wbuf[0];
4062 	for (i = 1; i < text.length; i++)
4063 	    wbuf[i - 1] = wbuf[i];
4064 	wbuf[i - 1] = wc;
4065 	buf = (char*)wbuf; /* so that it gets assigned and freed */
4066     }
4067     else {	/* thus text.format == XawFmt8Bit */
4068 	char c;
4069 
4070 	buf = _XawTextGetText(ctx, start, end);
4071 	text.length = (int)strlen(buf);
4072 	c = buf[0];
4073 	for (i = 1; i < text.length; i++)
4074 	    buf[i - 1] = buf[i];
4075 	buf[i - 1] = c;
4076     }
4077 
4078     text.ptr = buf;
4079 
4080     /* Store new text in source. */
4081 
4082     if (_XawTextReplace (ctx, start, end, &text))
4083 	XBell(XtDisplay(w), 0);
4084     XtFree((char *)buf);
4085     EndAction(ctx);
4086 }
4087 
4088 #ifndef OLDXAW
4089 /*ARGSUSED*/
4090 static void
4091 Undo(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4092 {
4093     TextWidget ctx = (TextWidget)w;
4094     int mul = MULT(ctx);
4095     Bool toggle = False;
4096 
4097     if (mul < 0) {
4098 	toggle = True;
4099 	_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
4100 	ctx->text.mult = (short)(mul = -mul);
4101     }
4102 
4103     StartAction(ctx, event);
4104     for (; mul; --mul)
4105 	if (!_XawTextSrcUndo((TextSrcObject)ctx->text.source, &ctx->text.insertPos))
4106 	    break;
4107     ctx->text.showposition = True;
4108 
4109     if (toggle)
4110 	_XawTextSrcToggleUndo((TextSrcObject)ctx->text.source);
4111     EndAction(ctx);
4112 }
4113 #endif
4114 
4115 /* NoOp() - action
4116  * This action performs no action, and allows the user or
4117  * application programmer to unbind a translation.
4118  *
4119  * Note: If the parameter list contains the string "RingBell" then
4120  *	 this action will ring the bell.
4121  */
4122 /*ARGSUSED*/
4123 static void
4124 NoOp(Widget w, XEvent *event _X_UNUSED, String *params, Cardinal *num_params)
4125 {
4126     if (*num_params != 1)
4127 	return;
4128 
4129     switch(params[0][0]) {
4130 	case 'R':
4131 	case 'r':
4132 	    XBell(XtDisplay(w), 0);
4133 	    /*FALLTROUGH*/
4134 	default:
4135 	    break;
4136     }
4137 }
4138 
4139 /* Reconnect() - action
4140  * This reconnects to the input method.  The user will typically call
4141  * this action if/when connection has been severed, or when the app
4142  * was started up before an IM was started up
4143  */
4144 /*ARGSUSED*/
4145 static void
4146 Reconnect(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4147 {
4148     _XawImReconnect(w);
4149 }
4150 
4151 #define	CAPITALIZE	1
4152 #define	DOWNCASE	2
4153 #define UPCASE		3
4154 
4155 #ifdef NO_LIBC_I18N
4156 static int
4157 ToLower(int ch)
4158 {
4159     char buf[2];
4160 
4161     *buf = ch;
4162     XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
4163 
4164     return (*buf);
4165 }
4166 
4167 static int
4168 ToUpper(int ch)
4169 {
4170     char buf[2];
4171 
4172     *buf = ch;
4173     XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
4174 
4175     return (*buf);
4176 }
4177 
4178 static int
4179 IsAlnum(int ch)
4180 {
4181     return ((ch >= '0' && ch <= '9') || ToUpper(ch) != ch || ToLower(ch) != ch);
4182 }
4183 
4184 static int
4185 IsLower(int ch)
4186 {
4187     char upbuf[2];
4188     char lobuf[2];
4189 
4190     *upbuf = *lobuf = ch;
4191     XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
4192     XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
4193 
4194     return (*lobuf != *upbuf && ch == *lobuf);
4195 }
4196 
4197 static int
4198 IsUpper(int ch)
4199 {
4200     char upbuf[2];
4201     char lobuf[2];
4202 
4203     *upbuf = *lobuf = ch;
4204     XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
4205     XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
4206 
4207     return (*lobuf != *upbuf && ch == *upbuf);
4208 }
4209 #else
4210 #define	ToLower	tolower
4211 #define ToUpper	toupper
4212 #define IsAlnum isalnum
4213 #define IsLower islower
4214 #define IsUpper isupper
4215 #endif
4216 
4217 static void
4218 CaseProc(Widget w, XEvent *event, int cmd)
4219 {
4220     TextWidget ctx = (TextWidget)w;
4221     short mul = MULT(ctx);
4222     XawTextPosition left, right;
4223     XawTextBlock block;
4224     Bool changed = False;
4225     unsigned char ch, mb[sizeof(wchar_t)];
4226     int i, count;
4227 
4228     if (mul > 0)
4229 	right = SrcScan(ctx->text.source, left = ctx->text.insertPos,
4230 			XawstAlphaNumeric, XawsdRight, mul, False);
4231     else
4232 	left = SrcScan(ctx->text.source, right = ctx->text.insertPos,
4233 		       XawstAlphaNumeric, XawsdLeft, 1 + -mul, False);
4234     block.firstPos = 0;
4235     block.format = (unsigned long)_XawTextFormat(ctx);
4236     block.length = (int)(right - left);
4237     block.ptr = _XawTextGetText(ctx, left, right);
4238 
4239     count = 0;
4240     if (block.format == XawFmt8Bit)
4241 	for (i = 0; i < block.length; i++) {
4242 	    if (!IsAlnum(*mb = (unsigned char)block.ptr[i]))
4243 		count = 0;
4244 	    else if (++count == 1 || cmd != CAPITALIZE) {
4245 		ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb));
4246 		if (ch != *mb) {
4247 		    changed = True;
4248 		    block.ptr[i] = (char)ch;
4249 		}
4250 	    }
4251 	    else if (cmd == CAPITALIZE) {
4252 		if ((ch = (unsigned char)(ToLower(*mb))) != *mb) {
4253 		    changed = True;
4254 		    block.ptr[i] = (char)ch;
4255 		}
4256 	    }
4257 	}
4258     else
4259 	for (i = 0; i < block.length; i++) {
4260 	    wctomb((char*)mb, ((wchar_t*)block.ptr)[i]);
4261 	    if (!IsAlnum(*mb))
4262 		count = 0;
4263 	    else if (++count == 1 || cmd != CAPITALIZE) {
4264 		ch = (unsigned char)((cmd == DOWNCASE) ? ToLower(*mb) : ToUpper(*mb));
4265 		if (ch != *mb) {
4266 		    changed = True;
4267 		    ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
4268 		}
4269 	    }
4270 	    else if (cmd == CAPITALIZE) {
4271 		if ((ch = (unsigned char)(ToLower(*mb))) != *mb) {
4272 		    changed = True;
4273 		    ((wchar_t*)block.ptr)[i] = _Xaw_atowc(ch);
4274 		}
4275 	    }
4276 	}
4277 
4278     StartAction(ctx, event);
4279     if (changed && _XawTextReplace(ctx, left, right, &block) != XawEditDone)
4280 	XBell(XtDisplay(ctx), 0);
4281     ctx->text.insertPos = right;
4282     EndAction(ctx);
4283 
4284     XtFree(block.ptr);
4285 }
4286 
4287 /*ARGSUSED*/
4288 static void
4289 CapitalizeWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4290 {
4291     CaseProc(w, event, CAPITALIZE);
4292 }
4293 
4294 /*ARGSUSED*/
4295 static void
4296 DowncaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4297 {
4298     CaseProc(w, event, DOWNCASE);
4299 }
4300 
4301 /*ARGSUSED*/
4302 static void
4303 UpcaseWord(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
4304 {
4305     CaseProc(w, event, UPCASE);
4306 }
4307 #undef CAPITALIZE
4308 #undef DOWNCASE
4309 #undef UPCASE
4310 
4311 XtActionsRec _XawTextActionsTable[] = {
4312   /* motion */
4313   {"forward-character",		MoveForwardChar},
4314   {"backward-character",	MoveBackwardChar},
4315   {"forward-word",		MoveForwardWord},
4316   {"backward-word",		MoveBackwardWord},
4317   {"forward-paragraph",		MoveForwardParagraph},
4318   {"backward-paragraph",	MoveBackwardParagraph},
4319   {"beginning-of-line",		MoveToLineStart},
4320   {"end-of-line",		MoveToLineEnd},
4321   {"next-line",			MoveNextLine},
4322   {"previous-line",		MovePreviousLine},
4323   {"next-page",			MoveNextPage},
4324   {"previous-page",		MovePreviousPage},
4325   {"beginning-of-file",		MoveBeginningOfFile},
4326   {"end-of-file",		MoveEndOfFile},
4327   {"scroll-one-line-up",	ScrollOneLineUp},
4328   {"scroll-one-line-down",	ScrollOneLineDown},
4329 
4330   /* delete */
4331   {"delete-next-character",	DeleteForwardChar},
4332   {"delete-previous-character",	DeleteBackwardChar},
4333   {"delete-next-word",		DeleteForwardWord},
4334   {"delete-previous-word",	DeleteBackwardWord},
4335   {"delete-selection",		DeleteCurrentSelection},
4336   {"delete",			Delete},
4337 
4338   /* kill */
4339   {"kill-word",			KillForwardWord},
4340   {"backward-kill-word",	KillBackwardWord},
4341   {"kill-selection",		KillCurrentSelection},
4342   {"kill-to-end-of-line",	KillToEndOfLine},
4343   {"kill-to-end-of-paragraph",	KillToEndOfParagraph},
4344 
4345   /* new line */
4346   {"newline-and-indent",	InsertNewLineAndIndent},
4347   {"newline-and-backup",	InsertNewLineAndBackup},
4348   {"newline",			InsertNewLine},
4349 
4350   /* selection */
4351   {"select-word",		SelectWord},
4352   {"select-all",		SelectAll},
4353   {"select-start",		SelectStart},
4354   {"select-adjust",		SelectAdjust},
4355   {"select-end",		SelectEnd},
4356   {"select-save",		SelectSave},
4357   {"extend-start",		ExtendStart},
4358   {"extend-adjust",		ExtendAdjust},
4359   {"extend-end", 		ExtendEnd},
4360   {"insert-selection",		InsertSelection},
4361 
4362   /* miscellaneous */
4363   {"redraw-display",		RedrawDisplay},
4364   {"insert-file",		_XawTextInsertFile},
4365   {"search",			_XawTextSearch},
4366   {"insert-char",		InsertChar},
4367   {"insert-string",		InsertString},
4368   {"focus-in",			TextFocusIn},
4369   {"focus-out",			TextFocusOut},
4370   {"enter-window",		TextEnterWindow},
4371   {"leave-window",		TextLeaveWindow},
4372   {"display-caret",		DisplayCaret},
4373   {"multiply",			Multiply},
4374   {"form-paragraph",		FormParagraph},
4375   {"transpose-characters",	TransposeCharacters},
4376   {"set-keyboard-focus",	SetKeyboardFocus},
4377 #ifndef OLDXAW
4378   {"numeric",			Numeric},
4379   {"undo",			Undo},
4380   {"keyboard-reset",		KeyboardReset},
4381   {"kill-ring-yank",		KillRingYank},
4382   {"toggle-overwrite",		ToggleOverwrite},
4383   {"indent",			Indent},
4384 #endif
4385   {"no-op",			NoOp},
4386 
4387   /* case transformations */
4388   {"capitalize-word",		CapitalizeWord},
4389   {"downcase-word",		DowncaseWord},
4390   {"upcase-word",		UpcaseWord},
4391 
4392   /* action to bind translations for text dialogs */
4393   {"InsertFileAction",		_XawTextInsertFileAction},
4394   {"DoSearchAction",		_XawTextDoSearchAction},
4395   {"DoReplaceAction",		_XawTextDoReplaceAction},
4396   {"SetField",			_XawTextSetField},
4397   {"PopdownSearchAction",	_XawTextPopdownSearchAction},
4398 
4399   /* reconnect to Input Method */
4400   {"reconnect-im",		Reconnect} /* Li Yuhong, Omron KK, 1991 */
4401 };
4402 
4403 Cardinal _XawTextActionsTableCount = XtNumber(_XawTextActionsTable);
4404