1 /*****************************************************************************
2  *
3  *  xdbx - X Window System interface to the dbx debugger
4  *
5  *  Copyright 1989 The University of Texas at Austin
6  *  Copyright 1990 Microelectronics and Computer Technology Corporation
7  *
8  *  Permission to use, copy, modify, and distribute this software and its
9  *  documentation for any purpose and without fee is hereby granted,
10  *  provided that the above copyright notice appear in all copies and that
11  *  both that copyright notice and this permission notice appear in
12  *  supporting documentation, and that the name of The University of Texas
13  *  and Microelectronics and Computer Technology Corporation (MCC) not be
14  *  used in advertising or publicity pertaining to distribution of
15  *  the software without specific, written prior permission.  The
16  *  University of Texas and MCC makes no representations about the
17  *  suitability of this software for any purpose.  It is provided "as is"
18  *  without express or implied warranty.
19  *
20  *  THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO
21  *  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  *  FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR
23  *  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
24  *  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
25  *  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26  *  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27  *
28  *  Author:  	Po Cheung
29  *  Created:   	March 10, 1989
30  *
31  *****************************************************************************
32  *
33  *  xxgdb - X Window System interface to the gdb debugger
34  *
35  * 	Copyright 1990,1993 Thomson Consumer Electronics, Inc.
36  *
37  *  Permission to use, copy, modify, and distribute this software and its
38  *  documentation for any purpose and without fee is hereby granted,
39  *  provided that the above copyright notice appear in all copies and that
40  *  both that copyright notice and this permission notice appear in
41  *  supporting documentation, and that the name of Thomson Consumer
42  *  Electronics (TCE) not be used in advertising or publicity pertaining
43  *  to distribution of the software without specific, written prior
44  *  permission.  TCE makes no representations about the suitability of
45  *  this software for any purpose.  It is provided "as is" without express
46  *  or implied warranty.
47  *
48  *  TCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
49  *  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
50  *  SHALL TCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
51  *  OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
52  *  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
53  *  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
54  *  SOFTWARE.
55  *
56  *  Adaptation to GDB:  Pierre Willard
57  *  XXGDB Created:   	December, 1990
58  *
59  *****************************************************************************/
60 
61 /*  dialog.c
62  *
63  *    Create the dialogue window where the user enter dbx commands, and
64  *    provide action procs to make a text widget behave like a terminal.
65  *
66  *    InsertSpace():	Prevent user from deleting past the prompt (action proc
67  *			for DELETE or BACKSPACE).
68  *    DeleteWord():	Word delete in dialog window. (action proc for Ctrl-w).
69  *    DeleteLine():	Line delete in dialog window. (action proc for Ctrl-u).
70  *    Dispatch():	Send an input command line to dbx. (action proc for CR).
71  *    SigInt():		Send SIGINT to dbx (action proc for Ctrl-C).
72  *    SigEof():		Send an EOF signal to dbx (action proc for Ctrl-D).
73  *    SigQuit():	Send SIGQUIT to dbx (action proc for Ctrl-\).
74  *    CreateDialogWindow(): Create dialog window and install action table.
75  *    AppendDialogText():       Append string to dialog window.
76  */
77 
78 #include <signal.h>
79 #include "global.h"
80 
81 #define	DIALOGSIZE	100000		/* max size of dialogue window buffer */
82 
83 Widget	dialogWindow;			/* text window as a dbx terminal */
84 Boolean FalseSignal = FALSE;		/* set to TRUE before self-generated
85 					   interrupt/quit signals */
86 static char DialogText[DIALOGSIZE];	/* text buffer for widget */
87 static XawTextPosition  StartPos;      	/* starting position of input text */
88 
89 
90 /*  This procedure prevents the user from deleting past the prompt, or
91  *  any text appended by AppendDialogText() to the dialog window.
92  *  It checks the last position of text, if it matches StartPos, set
93  *  by AppendDialogText(), it inserts a space so that delete-previous-
94  *  character() can only delete the space character.
95  */
96 /* ARGSUSED */
InsertSpace(w,event,params,num_params)97 static void InsertSpace(w, event, params, num_params)
98     Widget w;
99     XEvent *event;
100     String *params;
101     Cardinal *num_params;
102 {
103     XawTextBlock    textblock;
104     XawTextPosition lastPos;
105 
106     if (XawTextGetInsertionPoint(w) <= StartPos) {
107     	lastPos = TextGetLastPos(w);
108 	if (lastPos == StartPos) {
109 	    textblock.firstPos = 0;
110 	    textblock.length   = 1;
111 	    textblock.ptr      = " ";
112 	    XawTextReplace(w, lastPos, lastPos, &textblock);
113 	    XawTextSetInsertionPoint(w, lastPos+1);
114 	}
115     }
116 }
117 
118 /*  Erases the preceding word.
119  *  Simulates the action of the WERASE character (ctrl-W).
120  */
121 /* ARGSUSED */
DeleteWord(w,event,params,num_params)122 void DeleteWord(w, event, params, num_params)
123     Widget w;
124     XEvent *event;
125     String *params;
126     Cardinal *num_params;
127 {
128     XawTextBlock    	textblock;
129     XawTextPosition	pos;
130     Cardinal	 	i;
131 
132     textblock.firstPos = 0;
133     textblock.length   = 1;
134     textblock.ptr      = " ";
135 
136     pos = XawTextGetInsertionPoint(w);
137     if (pos <= StartPos)
138         pos = TextGetLastPos(w);
139     for (i=pos; i > StartPos && DialogText[i-1] == ' '; i--);
140     for (; i > StartPos && DialogText[i-1] != ' '; i--);
141     XawTextReplace(w, i, pos, &textblock);
142     XawTextSetInsertionPoint(w, i);
143 }
144 
145 /*  Erases the preceding word.
146  *  Simulates the action of the WERASE character (ctrl-W).
147  */
148 /* ARGSUSED */
DeleteChar(w,event,params,num_params)149 void DeleteChar(w, event, params, num_params)
150     Widget w;
151     XEvent *event;
152     String *params;
153     Cardinal *num_params;
154 {
155     XawTextBlock    	textblock;
156     XawTextPosition	pos;
157 
158     textblock.firstPos = 0;
159     textblock.length   = 1;
160     textblock.ptr      = " ";
161 
162     pos = XawTextGetInsertionPoint(w);
163     if (pos > StartPos) {
164     	XawTextReplace(w, pos-1, pos, &textblock);
165     	XawTextSetInsertionPoint(w, pos-1);
166     }
167 }
168 
169 
170 /*  Deletes the entire current input line.
171  *  simulates the action of the KILL character (ctrl-U).
172  */
173 /* ARGSUSED */
DeleteLine(w,event,params,num_params)174 void DeleteLine(w, event, params, num_params)
175     Widget w;
176     XEvent *event;
177     String *params;
178     Cardinal *num_params;
179 {
180     XawTextBlock    	textblock;
181     XawTextPosition 	pos, beginPos;
182     Cardinal	 	i;
183     char		*s;
184 
185     textblock.firstPos = 0;
186     textblock.length   = 1;
187     textblock.ptr      = " ";
188 
189     pos = XawTextGetInsertionPoint(w);
190     if (w == dialogWindow) {
191 	s = DialogText;
192 	beginPos = StartPos;
193 	if (pos <= beginPos)
194     	    pos = TextGetLastPos(w);
195     } else {
196 		return;
197 	}
198     for (i=pos; i > beginPos && s[i-1] != '\n'; i--);
199     XawTextReplace(w, i, pos, &textblock);
200     XawTextSetInsertionPoint(w, i);
201 }
202 
203 
204 /*  Dispatch() is invoked on every <CR>.
205  *  It collects text from the dialog window and sends it to dbx.
206  *  If the string is a command to dbx (Prompt would be TRUE),
207  *  it is stored in the global variable, Command.
208  */
209 /* ARGSUSED */
Dispatch(w,event,params,num_params)210 static void Dispatch(w, event, params, num_params)
211     Widget w;
212     XEvent *event;
213     String *params;
214     Cardinal *num_params;
215 {
216 #ifdef GDB
217 	/*
218 	For GDB, '\n' means exec previous command again.
219 	default command is space+CR, so that we never send
220 	CR to gdb (the repeat is managed here)
221 	*/
222     static char gdb_command[LINESIZ] = " \n";
223 #endif
224 char s[LINESIZ];
225 
226     strcpy(s, DialogText + StartPos);
227 #if 1
228 	/* (PW)18DEC90 : bug xdbx : without the following line,
229 	xdbx sends several times the same lines when Prompt is false */
230     StartPos = TextGetLastPos(dialogWindow);
231 #endif
232 
233     if (Prompt)
234     	{
235 #ifdef GDB
236 		/* When we send \n to gdb, it executes the last command,
237 		so better tell xxgdb what gdb is doing */
238 	    if (strcmp(s, "\n"))
239 			strcpy(gdb_command,s);	/* if not "\n" ! */
240 	    else
241 	    	{
242 	    	/* copy previous command in new command, and
243 	    	echo the command in the dialog window. */
244 			strcpy(s,gdb_command);
245 			AppendDialogText(gdb_command);
246 			}
247 #endif /* GDB */
248 		send_command (s);
249 		}
250 	else
251 		/* this string is for the application, not for gdb */
252     	write_dbx(s);
253 }
254 
255 /*  Sends an interrupt signal, SIGINT, to dbx.
256  *  Simulates the action of the INTR character (ctrl-C).
257  */
signal_interrupt_dbx()258 void signal_interrupt_dbx()
259 {
260 #ifndef GDB
261     FalseSignal = TRUE;
262 #ifdef SYSV /* (PW)13AUG92:  change SVR4 into SYSV */ /* (MJH) */
263    kill(-(dbxpid), SIGINT);
264 #else
265    killpg(dbxpid, SIGINT);
266 #endif /* SYSV */
267 #else
268 	write_dbx("\003");	/* (PW)18FEB91 : seems to work better */
269 #endif	/* GDB */
270 }
271 
272 /*  Sends an interrupt signal, SIGINT, to dbx.
273  *  Simulates the action of the INTR character (ctrl-C).
274  */
275 /* ARGSUSED */
SigInt(w,event,params,num_params)276 static void SigInt(w, event, params, num_params)
277     Widget w;
278     XEvent *event;
279     String *params;
280     Cardinal *num_params;
281 {
282   signal_interrupt_dbx ();
283 }
284 
285 /*  Sends an EOF signal to dbx. (ctrl-D) */
286 /* ARGSUSED */
SigEof(w,event,params,num_params)287 static void SigEof(w, event, params, num_params)
288     Widget w;
289     XEvent *event;
290     String *params;
291     Cardinal *num_params;
292 {
293     write_dbx("\04");
294 }
295 
296 
297 /*  Sends a QUIT signal, SIGQUIT, to dbx.
298  *  Simulates the action of the QUIT character (ctrl-\)
299  */
300 /* ARGSUSED */
SigQuit(w,event,params,num_params)301 static void SigQuit(w, event, params, num_params)
302     Widget w;
303     XEvent *event;
304     String *params;
305     Cardinal *num_params;
306 {
307     FalseSignal = TRUE;
308 
309 #ifdef SYSV /* (PW)13AUG92:  change SVR4 into SYSV */ /* (MJH) */
310     kill(-(dbxpid), SIGQUIT);
311 #else
312     killpg(dbxpid, SIGQUIT);
313 #endif /* SYSV */
314 }
315 
316 
317 /*
318  *  Dialog window has its own set of translations for editing.
319  *  Special action procedures for keys Delete/Backspace, Carriage Return,
320  *  Ctrl-U, Ctrl-C, Ctrl-D, Ctrl-\, and word selection.
321  */
CreateDialogWindow(parent)322 void CreateDialogWindow(parent)
323 Widget parent;
324 {
325     Arg 	args[MAXARGS];
326     Cardinal 	n;
327 
328     static XtActionsRec dialog_actions[] = {
329 	{"SigInt", 	(XtActionProc) SigInt},
330 	{"SigEof", 	(XtActionProc) SigEof},
331 	{"SigQuit", 	(XtActionProc) SigQuit},
332 	{"InsertSpace", (XtActionProc) InsertSpace},
333 	{"Dispatch", 	(XtActionProc) Dispatch},
334 	{"DeleteChar", 	(XtActionProc) DeleteChar},
335         {NULL, NULL}
336     };
337 
338     static String translations = "#override\n\
339  	Ctrl<Key>C:	SigInt()\n\
340  	Ctrl<Key>D:	SigEof()\n\
341  	Ctrl<Key>|:	SigQuit()\n\
342  	Ctrl<Key>W:	DeleteWord()\n\
343  	Ctrl<Key>U:	DeleteLine()\n\
344  	Ctrl<Key>H:	DeleteChar()\n\
345  	<Key>Delete:	DeleteChar()\n\
346  	<Key>BackSpace:	DeleteChar()\n\
347  	<Key>Return:	newline()Dispatch()\n\
348     ";
349 
350     n = 0;
351     XtSetArg(args[n], XtNuseStringInPlace, True);                       n++;
352     XtSetArg(args[n], XtNstring, (XtArgVal) DialogText);		n++;
353     XtSetArg(args[n], XtNlength, (XtArgVal) DIALOGSIZE);		n++;
354     XtSetArg(args[n], XtNeditType, (XtArgVal) XawtextAppend);		n++;
355     XtSetArg(args[n], XtNscrollVertical, XawtextScrollAlways);		n++;
356     XtSetArg(args[n], XtNwrap, XawtextWrapWord);			n++;
357     dialogWindow = XtCreateManagedWidget("dialogWindow", asciiTextWidgetClass,
358 					 parent, args, n );
359     XtOverrideTranslations(dialogWindow, XtParseTranslationTable(translations));
360     XtAppAddActions(app_context, dialog_actions, XtNumber(dialog_actions));
361 }
362 
363 #if 0 /* never used */
364 static void TextSetLastPos(w, lastPos)
365 Widget w;
366 XawTextPosition lastPos;
367 {
368     TextWidget ctx = (TextWidget) w;
369     ctx->text.lastPos = lastPos;
370 }
371 #endif
372 
AppendDialogText(s)373 void AppendDialogText(s)
374     char   *s;
375 {
376     XawTextPosition     i, lastPos;
377     XawTextBlock        textblock, nullblock;
378 
379     if (!s || !strcmp(s, "")) return;
380 
381 	if (debug) {
382 		fprintf(stderr, "AppendDialogText \"%s\"\n", s);
383 	}
384 
385     textblock.firstPos = 0;
386     textblock.length   = strlen(s);
387     textblock.ptr      = s;
388 
389     lastPos = TextGetLastPos(dialogWindow);
390     if (textblock.length > DIALOGSIZE) {
391 	bell(0);
392 #ifdef GDB
393 	fprintf(stderr, "xxgdb error: cannot display string in dialogue window\n\
394             string has %d bytes; dialogue window size limit is %d bytes\n",
395 	    textblock.length, DIALOGSIZE);
396 #else
397 	fprintf(stderr, "xdbx error: cannot display string in dialogue window\n\
398             string has %d bytes; dialogue window size limit is %d bytes\n",
399 	    textblock.length, DIALOGSIZE);
400 #endif
401         return;
402     }
403     if (lastPos + textblock.length > DIALOGSIZE) {
404 	nullblock.firstPos = 0;
405 	nullblock.length = 0;
406 	nullblock.ptr = "";
407 
408 	i = textblock.length - (DIALOGSIZE - lastPos);
409 	if (i < 0.9*DIALOGSIZE)
410 	    i += 0.1*DIALOGSIZE;
411         while (DialogText[i] != '\n') i++;
412         XawTextReplace(dialogWindow, 0, i+1, &nullblock);
413     	lastPos = TextGetLastPos(dialogWindow);
414     }
415     XawTextReplace(dialogWindow, lastPos, lastPos, &textblock);
416     StartPos = TextGetLastPos(dialogWindow);
417     XawTextSetInsertionPoint(dialogWindow, StartPos);
418 
419 #if 0 /* no longer necessary I think */
420 /* fix annoying bug that dialog mark is sometimes scrolled off bottom (widget bug?) */
421     XawTextDisplay(dialogWindow);
422 #endif
423 
424 #if defined(OLDSUNOS)||defined(SUNOS4)
425 /* Have experienced bug where dialog window actually writes off bottom
426 (does not scroll to bottom).  Seems more prevalent with Openwindows,
427 but since it needs to debug certain programs to get this to show up.
428 Couldn't find the problem, but this works around it: (really icky but
429 only way I found to fix it) */
430 
431     if (StartPos >= ((TextWidget)dialogWindow)->text.lt.info[((TextWidget)dialogWindow)->text.lt.lines].position)
432        XtCallActionProc(dialogWindow, "redraw-display", 0, 0, 0);
433 #endif /* SUNOS */
434 }
435 
436