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