* gdbtk.c (gdbtk_flush gdbtk_fputs): Buffer up output to make
[deliverable/binutils-gdb.git] / gdb / gdbtk.c
CommitLineData
754e5da2
SG
1/* TK interface routines.
2 Copyright 1994 Free Software Foundation, Inc.
3
4This file is part of GDB.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "defs.h"
21#include "symtab.h"
22#include "inferior.h"
23#include "command.h"
24#include "bfd.h"
25#include "symfile.h"
26#include "objfiles.h"
27#include "target.h"
28#include <sys/types.h>
29#include <sys/time.h>
30#include <sys/param.h>
31#include <varargs.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <sys/filio.h>
35#include <setjmp.h>
36#include <signal.h>
37#include <sys/errno.h>
38#include <termios.h>
39#include <string.h>
40#include <tcl.h>
41#include <tk.h>
8532893d 42#include <unistd.h>
754e5da2
SG
43
44/* Non-zero means that we're doing the gdbtk interface. */
45int gdbtk = 0;
46
47/* Non-zero means we are reloading breakpoints, etc from the
48 Gdbtk kernel, and we should suppress various messages */
49static int gdbtk_reloading = 0;
50
51/* Handle for TCL interpreter */
52static Tcl_Interp *interp = NULL;
53
54/* Handle for TK main window */
55static Tk_Window mainWindow = NULL;
56
57static void
58null_routine(arg)
59 int arg;
60{
61}
62
63\f
64/* This routine redirects the output of fputs_unfiltered so that
65 the user can see what's going on in his debugger window. */
66
8532893d
SG
67static char holdbuf[200];
68static char *holdbufp = holdbuf;
69static int holdfree = sizeof (holdbuf);
70
754e5da2 71static void
8532893d 72flush_holdbuf ()
754e5da2 73{
8532893d
SG
74 if (holdbufp == holdbuf)
75 return;
76
77 Tcl_VarEval (interp, "gdbtk_tcl_fputs ", "{", holdbuf, "}", NULL);
78 holdbufp = holdbuf;
79 holdfree = sizeof (holdbuf);
754e5da2
SG
80}
81
82static void
83gdbtk_flush (stream)
84 FILE *stream;
85{
8532893d
SG
86 flush_holdbuf ();
87
754e5da2
SG
88 Tcl_VarEval (interp, "gdbtk_tcl_flush", NULL);
89}
90
8532893d
SG
91static void
92gdbtk_fputs (ptr)
93 const char *ptr;
94{
95 int len;
96
97 len = strlen (ptr) + 1;
98
99 if (len > holdfree)
100 {
101 flush_holdbuf ();
102
103 if (len > sizeof (holdbuf))
104 {
105 Tcl_VarEval (interp, "gdbtk_tcl_fputs ", "{", ptr, "}", NULL);
106 return;
107 }
108 }
109
110 strncpy (holdbufp, ptr, len);
111 holdbufp += len - 1;
112 holdfree -= len - 1;
113}
114
754e5da2
SG
115static int
116gdbtk_query (args)
117 va_list args;
118{
119 char *query;
120 char buf[200];
121 long val;
122
123 query = va_arg (args, char *);
124
125 vsprintf(buf, query, args);
126 Tcl_VarEval (interp, "gdbtk_tcl_query ", "{", buf, "}", NULL);
127
128 val = atol (interp->result);
129 return val;
130}
131\f
132static char *
133full_filename(symtab)
134 struct symtab *symtab;
135{
136 int pathlen;
137 char *filename;
138
139 if (!symtab)
140 return NULL;
141
142 if (symtab->fullname)
143 return savestring(symtab->fullname, strlen(symtab->fullname));
144
145 if (symtab->filename[0] == '/')
146 return savestring(symtab->filename, strlen(symtab->filename));
147
148 if (symtab->dirname)
149 pathlen = strlen(symtab->dirname);
150 else
151 pathlen = 0;
152 if (symtab->filename)
153 pathlen += strlen(symtab->filename);
154
155 filename = xmalloc(pathlen+1);
156
157 if (symtab->dirname)
158 strcpy(filename, symtab->dirname);
159 else
160 *filename = '\000';
161 if (symtab->filename)
162 strcat(filename, symtab->filename);
163
164 return filename;
165}
166\f
167static void
168breakpoint_notify(b, action)
169 struct breakpoint *b;
170 const char *action;
171{
172 struct symbol *sym;
8532893d 173 char bpnum[50], line[50], pc[50];
754e5da2
SG
174 struct symtab_and_line sal;
175 char *filename;
176 int v;
177
178 if (b->type != bp_breakpoint)
179 return;
180
181 sal = find_pc_line (b->address, 0);
182
183 filename = full_filename (sal.symtab);
184
185 sprintf (bpnum, "%d", b->number);
186 sprintf (line, "%d", sal.line);
8532893d 187 sprintf (pc, "0x%x", b->address);
754e5da2
SG
188
189 v = Tcl_VarEval (interp,
190 "gdbtk_tcl_breakpoint ",
191 action,
192 " ", bpnum,
193 " ", filename,
194 " ", line,
8532893d 195 " ", pc,
754e5da2
SG
196 NULL);
197
198 if (v != TCL_OK)
199 {
200 gdbtk_fputs (interp->result);
201 gdbtk_fputs ("\n");
202 }
203
204 if (filename)
205 free (filename);
206}
207
208static void
209gdbtk_create_breakpoint(b)
210 struct breakpoint *b;
211{
212 breakpoint_notify(b, "create");
213}
214
215static void
216gdbtk_delete_breakpoint(b)
217 struct breakpoint *b;
218{
219 breakpoint_notify(b, "delete");
220}
221
222static void
223gdbtk_enable_breakpoint(b)
224 struct breakpoint *b;
225{
226 breakpoint_notify(b, "enable");
227}
228
229static void
230gdbtk_disable_breakpoint(b)
231 struct breakpoint *b;
232{
233 breakpoint_notify(b, "disable");
234}
235\f
236/* This implements the TCL command `gdb_loc', which returns a list consisting
237 of the source and line number associated with the current pc. */
238
239static int
240gdb_loc (clientData, interp, argc, argv)
241 ClientData clientData;
242 Tcl_Interp *interp;
243 int argc;
244 char *argv[];
245{
246 char *filename;
247 char buf[100];
248 struct symtab_and_line sal;
249 char *funcname;
8532893d 250 CORE_ADDR pc;
754e5da2
SG
251
252 if (argc == 1)
253 {
254 struct frame_info *frame;
255 struct symbol *func;
754e5da2
SG
256
257 frame = get_frame_info (selected_frame);
8532893d 258
754e5da2 259 pc = frame ? frame->pc : stop_pc;
8532893d 260
754e5da2
SG
261 sal = find_pc_line (pc, 0);
262 }
263 else if (argc == 2)
264 {
754e5da2 265 struct symtabs_and_lines sals;
8532893d 266 int nelts;
754e5da2
SG
267
268 sals = decode_line_spec (argv[1], 1);
269
8532893d
SG
270 nelts = sals.nelts;
271 sal = sals.sals[0];
272 free (sals.sals);
273
754e5da2
SG
274 if (sals.nelts != 1)
275 {
276 Tcl_SetResult (interp, "Ambiguous line spec", TCL_STATIC);
754e5da2
SG
277 return TCL_ERROR;
278 }
279
8532893d 280 pc = sal.pc;
754e5da2
SG
281 }
282 else
283 {
284 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
285 return TCL_ERROR;
286 }
287
754e5da2
SG
288 if (sal.symtab)
289 Tcl_AppendElement (interp, sal.symtab->filename);
290 else
291 Tcl_AppendElement (interp, "");
8532893d
SG
292
293 find_pc_partial_function (pc, &funcname, NULL, NULL);
754e5da2 294 Tcl_AppendElement (interp, funcname);
8532893d
SG
295
296 filename = full_filename (sal.symtab);
754e5da2 297 Tcl_AppendElement (interp, filename);
8532893d
SG
298
299 sprintf (buf, "%d", sal.line);
754e5da2
SG
300 Tcl_AppendElement (interp, buf); /* line number */
301
8532893d
SG
302 sprintf (buf, "0x%x", pc);
303 Tcl_AppendElement (interp, buf); /* PC */
304
754e5da2
SG
305 if (filename)
306 free(filename);
307
308 return TCL_OK;
309}
310\f
311static int
312gdb_cmd_stub (cmd)
313 char *cmd;
314{
315 execute_command (cmd, 1);
316
317 return 1; /* Indicate success */
318}
319
320/* This implements the TCL command `gdb_cmd', which sends it's argument into
321 the GDB command scanner. */
322
323static int
324gdb_cmd (clientData, interp, argc, argv)
325 ClientData clientData;
326 Tcl_Interp *interp;
327 int argc;
328 char *argv[];
329{
330 int val;
331 struct cleanup *old_chain;
332
333 if (argc != 2)
334 {
335 Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
336 return TCL_ERROR;
337 }
338
339 old_chain = make_cleanup (null_routine, 0);
340
341 val = catch_errors (gdb_cmd_stub, argv[1], "", RETURN_MASK_ERROR);
342
343 bpstat_do_actions (&stop_bpstat);
344 do_cleanups (old_chain);
345
8532893d
SG
346 /* Drain all buffered command output */
347
348 gdb_flush (gdb_stderr);
349 gdb_flush (gdb_stdout);
350
754e5da2
SG
351 /* We could base the return value on val, but that would require most users
352 to use catch. Since GDB errors are already being handled elsewhere, I
353 see no reason to pass them up to the caller. */
354
355 return TCL_OK;
356}
357
358static int
359gdb_listfiles (clientData, interp, argc, argv)
360 ClientData clientData;
361 Tcl_Interp *interp;
362 int argc;
363 char *argv[];
364{
365 int val;
366 struct objfile *objfile;
367 struct partial_symtab *psymtab;
368
369 ALL_PSYMTABS (objfile, psymtab)
370 Tcl_AppendElement (interp, psymtab->filename);
371
372 return TCL_OK;
373}
374\f
375static void
376tk_command (cmd, from_tty)
377 char *cmd;
378 int from_tty;
379{
380 Tcl_VarEval (interp, cmd, NULL);
381
382 gdbtk_fputs (interp->result);
383 gdbtk_fputs ("\n");
384}
385
386static void
387cleanup_init (ignored)
388 int ignored;
389{
390 if (mainWindow != NULL)
391 Tk_DestroyWindow (mainWindow);
392 mainWindow = NULL;
393
394 if (interp != NULL)
395 Tcl_DeleteInterp (interp);
396 interp = NULL;
397}
398
399static void
400gdbtk_init ()
401{
402 struct cleanup *old_chain;
403 char *gdbtk_filename;
404
405 old_chain = make_cleanup (cleanup_init, 0);
406
407 /* First init tcl and tk. */
408
409 interp = Tcl_CreateInterp ();
410
411 if (!interp)
412 error ("Tcl_CreateInterp failed");
413
414 mainWindow = Tk_CreateMainWindow (interp, NULL, "gdb", "Gdb");
415
416 if (!mainWindow)
417 return; /* DISPLAY probably not set */
418
419 if (Tcl_Init(interp) != TCL_OK)
420 error ("Tcl_Init failed: %s", interp->result);
421
422 if (Tk_Init(interp) != TCL_OK)
423 error ("Tk_Init failed: %s", interp->result);
424
425 Tcl_CreateCommand (interp, "gdb_cmd", gdb_cmd, NULL, NULL);
426 Tcl_CreateCommand (interp, "gdb_loc", gdb_loc, NULL, NULL);
427 Tcl_CreateCommand (interp, "gdb_listfiles", gdb_listfiles, NULL, NULL);
428
429 gdbtk_filename = getenv ("GDBTK_FILENAME");
8532893d
SG
430 if (!gdbtk_filename)
431 if (access ("gdbtk.tcl", R_OK) == 0)
432 gdbtk_filename = "gdbtk.tcl";
433 else
434 gdbtk_filename = GDBTK_FILENAME;
435
436 if (Tcl_EvalFile (interp, gdbtk_filename) != TCL_OK)
437 error ("Failure reading %s: %s", gdbtk_filename, interp->result);
754e5da2
SG
438
439 command_loop_hook = Tk_MainLoop;
440 fputs_unfiltered_hook = gdbtk_fputs;
441 print_frame_info_listing_hook = null_routine;
442 query_hook = gdbtk_query;
443 flush_hook = gdbtk_flush;
444 create_breakpoint_hook = gdbtk_create_breakpoint;
445 delete_breakpoint_hook = gdbtk_delete_breakpoint;
446 enable_breakpoint_hook = gdbtk_enable_breakpoint;
447 disable_breakpoint_hook = gdbtk_disable_breakpoint;
448
449 discard_cleanups (old_chain);
450
451 add_com ("tk", class_obscure, tk_command,
452 "Send a command directly into tk.");
453}
454
455/* Come here during initialze_all_files () */
456
457void
458_initialize_gdbtk ()
459{
460 if (no_windows)
461 return;
462
463 /* Tell the rest of the world that Gdbtk is now set up. */
464
465 init_ui_hook = gdbtk_init;
466}
This page took 0.045116 seconds and 4 git commands to generate.