]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tui.c
* tuiWin.c (tui_update_gdb_sizes): New function to tell gdb what
[thirdparty/binutils-gdb.git] / gdb / tui / tui.c
1 /* General functions for the WDB TUI.
2
3 Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation,
4 Inc.
5
6 Contributed by Hewlett-Packard Company.
7
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
24
25 /* FIXME: cagney/2002-02-28: The GDB coding standard indicates that
26 "defs.h" should be included first. Unfortunatly some systems
27 (currently Debian GNU/Linux) include the <stdbool.h> via <curses.h>
28 and they clash with "bfd.h"'s definiton of true/false. The correct
29 fix is to remove true/false from "bfd.h", however, until that
30 happens, hack around it by including "config.h" and <curses.h>
31 first. */
32
33 #include "config.h"
34 #ifdef HAVE_NCURSES_H
35 #include <ncurses.h>
36 #else
37 #ifdef HAVE_CURSES_H
38 #include <curses.h>
39 #endif
40 #endif
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <ctype.h>
45 #include <malloc.h>
46 #ifdef HAVE_TERM_H
47 #include <term.h>
48 #endif
49 #include <signal.h>
50 #include <fcntl.h>
51 #if 0
52 #include <termio.h>
53 #endif
54 #include <setjmp.h>
55 #include "defs.h"
56 #include "gdbcmd.h"
57 #include "tui.h"
58 #include "tuiData.h"
59 #include "tuiLayout.h"
60 #include "tuiIO.h"
61 #include "tuiRegs.h"
62 #include "tuiStack.h"
63 #include "tuiWin.h"
64 #include "tuiSourceWin.h"
65 #include "readline/readline.h"
66 #include "target.h"
67 #include "frame.h"
68 #include "breakpoint.h"
69 #include "inferior.h"
70
71 /* Tells whether the TUI is active or not. */
72 int tui_active = 0;
73 static int tui_finish_init = 1;
74
75 /* Switch the output mode between TUI/standard gdb. */
76 static int
77 tui_switch_mode (void)
78 {
79 if (tui_active)
80 {
81 tui_disable ();
82 rl_prep_terminal (0);
83
84 printf_filtered ("Left the TUI mode\n");
85 }
86 else
87 {
88 rl_deprep_terminal ();
89 tui_enable ();
90 printf_filtered ("Entered the TUI mode\n");
91 }
92
93 /* Clear the readline in case switching occurred in middle of something. */
94 if (rl_end)
95 rl_kill_text (0, rl_end);
96
97 /* Since we left the curses mode, the terminal mode is restored to
98 some previous state. That state may not be suitable for readline
99 to work correctly (it may be restored in line mode). We force an
100 exit of the current readline so that readline is re-entered and it
101 will be able to setup the terminal for its needs. By re-entering
102 in readline, we also redisplay its prompt in the non-curses mode. */
103 rl_newline (1, '\n');
104
105 /* Make sure the \n we are returning does not repeat the last command. */
106 dont_repeat ();
107 return 0;
108 }
109
110 /* Change the TUI layout to show a next layout.
111 This function is bound to CTRL-X 2. It is intended to provide
112 a functionality close to the Emacs split-window command. We always
113 show two windows (src+asm), (src+regs) or (asm+regs). */
114 static int
115 tui_change_windows (void)
116 {
117 if (!tui_active)
118 tui_switch_mode ();
119
120 if (tui_active)
121 {
122 TuiLayoutType new_layout;
123 TuiRegisterDisplayType regs_type = TUI_UNDEFINED_REGS;
124
125 new_layout = currentLayout ();
126
127 /* Select a new layout to have a rolling layout behavior
128 with always two windows (except when undefined). */
129 switch (new_layout)
130 {
131 case SRC_COMMAND:
132 new_layout = SRC_DISASSEM_COMMAND;
133 break;
134
135 case DISASSEM_COMMAND:
136 new_layout = SRC_DISASSEM_COMMAND;
137 break;
138
139 case SRC_DATA_COMMAND:
140 new_layout = SRC_DISASSEM_COMMAND;
141 break;
142
143 case SRC_DISASSEM_COMMAND:
144 new_layout = DISASSEM_DATA_COMMAND;
145 break;
146
147 case DISASSEM_DATA_COMMAND:
148 new_layout = SRC_DATA_COMMAND;
149 break;
150
151 default:
152 new_layout = SRC_COMMAND;
153 break;
154 }
155 tuiSetLayout (new_layout, regs_type);
156 }
157 return 0;
158 }
159
160
161 /* Delete the second TUI window to only show one. */
162 static int
163 tui_delete_other_windows (void)
164 {
165 if (!tui_active)
166 tui_switch_mode ();
167
168 if (tui_active)
169 {
170 TuiLayoutType new_layout;
171 TuiRegisterDisplayType regs_type = TUI_UNDEFINED_REGS;
172
173 new_layout = currentLayout ();
174
175 /* Kill one window. */
176 switch (new_layout)
177 {
178 case SRC_COMMAND:
179 case SRC_DATA_COMMAND:
180 case SRC_DISASSEM_COMMAND:
181 default:
182 new_layout = SRC_COMMAND;
183 break;
184
185 case DISASSEM_COMMAND:
186 case DISASSEM_DATA_COMMAND:
187 new_layout = DISASSEM_COMMAND;
188 break;
189 }
190 tuiSetLayout (new_layout, regs_type);
191 }
192 return 0;
193 }
194
195 /* Initialize readline and configure the keymap for the switching
196 key shortcut. */
197 void
198 tui_initialize_readline ()
199 {
200 rl_initialize ();
201
202 rl_add_defun ("tui-switch-mode", tui_switch_mode, -1);
203 rl_bind_key_in_map ('a', tui_switch_mode, emacs_ctlx_keymap);
204 rl_bind_key_in_map ('A', tui_switch_mode, emacs_ctlx_keymap);
205 rl_bind_key_in_map (CTRL ('A'), tui_switch_mode, emacs_ctlx_keymap);
206 rl_bind_key_in_map ('1', tui_delete_other_windows, emacs_ctlx_keymap);
207 rl_bind_key_in_map ('2', tui_change_windows, emacs_ctlx_keymap);
208 }
209
210 /* Enter in the tui mode (curses).
211 When in normal mode, it installs the tui hooks in gdb, redirects
212 the gdb output, configures the readline to work in tui mode.
213 When in curses mode, it does nothing. */
214 void
215 tui_enable (void)
216 {
217 if (tui_active)
218 return;
219
220 /* To avoid to initialize curses when gdb starts, there is a defered
221 curses initialization. This initialization is made only once
222 and the first time the curses mode is entered. */
223 if (tui_finish_init)
224 {
225 WINDOW *w;
226
227 w = initscr ();
228
229 cbreak ();
230 noecho ();
231 /*timeout (1);*/
232 nodelay(w, FALSE);
233 nl();
234 keypad (w, TRUE);
235 rl_initialize ();
236 setTermHeightTo (LINES);
237 setTermWidthTo (COLS);
238 def_prog_mode ();
239
240 tuiShowFrameInfo (0);
241 tuiSetLayout (SRC_COMMAND, TUI_UNDEFINED_REGS);
242 tuiSetWinFocusTo (srcWin);
243 keypad (cmdWin->generic.handle, TRUE);
244 wrefresh (cmdWin->generic.handle);
245 tui_finish_init = 0;
246 }
247 else
248 {
249 /* Save the current gdb setting of the terminal.
250 Curses will restore this state when endwin() is called. */
251 def_shell_mode ();
252 clearok (stdscr, TRUE);
253 }
254
255 /* Install the TUI specific hooks. */
256 tui_install_hooks ();
257
258 tui_update_variables ();
259
260 tui_setup_io (1);
261
262 tui_version = 1;
263 tui_active = 1;
264 refresh ();
265 tui_update_gdb_sizes ();
266 }
267
268 /* Leave the tui mode.
269 Remove the tui hooks and configure the gdb output and readline
270 back to their original state. The curses mode is left so that
271 the terminal setting is restored to the point when we entered. */
272 void
273 tui_disable (void)
274 {
275 if (!tui_active)
276 return;
277
278 /* Remove TUI hooks. */
279 tui_remove_hooks ();
280
281 /* Leave curses and restore previous gdb terminal setting. */
282 endwin ();
283
284 /* gdb terminal has changed, update gdb internal copy of it
285 so that terminal management with the inferior works. */
286 tui_setup_io (0);
287
288 tui_version = 0;
289 tui_active = 0;
290 tui_update_gdb_sizes ();
291 }
292
293 /* Wrapper on top of free() to ensure that input address
294 is greater than 0x0. */
295 void
296 tuiFree (char *ptr)
297 {
298 if (ptr != (char *) NULL)
299 {
300 xfree (ptr);
301 }
302 }
303
304 /* Determine what the low address will be to display in the TUI's
305 disassembly window. This may or may not be the same as the
306 low address input. */
307 CORE_ADDR
308 tuiGetLowDisassemblyAddress (CORE_ADDR low, CORE_ADDR pc)
309 {
310 int line;
311 CORE_ADDR newLow;
312
313 /* Determine where to start the disassembly so that the pc is about in the
314 middle of the viewport. */
315 for (line = 0, newLow = pc;
316 (newLow > low &&
317 line < (tuiDefaultWinViewportHeight (DISASSEM_WIN,
318 DISASSEM_COMMAND) / 2));)
319 {
320 bfd_byte buffer[4];
321
322 newLow -= sizeof (bfd_getb32 (buffer));
323 line++;
324 }
325
326 return newLow;
327 }
328
329 void
330 strcat_to_buf (char *buf, int buflen, char *itemToAdd)
331 {
332 if (itemToAdd != (char *) NULL && buf != (char *) NULL)
333 {
334 if ((strlen (buf) + strlen (itemToAdd)) <= buflen)
335 strcat (buf, itemToAdd);
336 else
337 strncat (buf, itemToAdd, (buflen - strlen (buf)));
338 }
339 }
340
341 #if 0
342 /* Solaris <sys/termios.h> defines CTRL. */
343 #ifndef CTRL
344 #define CTRL(x) (x & ~0140)
345 #endif
346
347 #define FILEDES 2
348 #define CHK(val, dft) (val<=0 ? dft : val)
349
350 static void
351 _tuiReset (void)
352 {
353 struct termio mode;
354
355 /*
356 ** reset the teletype mode bits to a sensible state.
357 ** Copied tset.c
358 */
359 #if ! defined (USG) && defined (TIOCGETC)
360 struct tchars tbuf;
361 #endif /* !USG && TIOCGETC */
362 #ifdef UCB_NTTY
363 struct ltchars ltc;
364
365 if (ldisc == NTTYDISC)
366 {
367 ioctl (FILEDES, TIOCGLTC, &ltc);
368 ltc.t_suspc = CHK (ltc.t_suspc, CTRL ('Z'));
369 ltc.t_dsuspc = CHK (ltc.t_dsuspc, CTRL ('Y'));
370 ltc.t_rprntc = CHK (ltc.t_rprntc, CTRL ('R'));
371 ltc.t_flushc = CHK (ltc.t_flushc, CTRL ('O'));
372 ltc.t_werasc = CHK (ltc.t_werasc, CTRL ('W'));
373 ltc.t_lnextc = CHK (ltc.t_lnextc, CTRL ('V'));
374 ioctl (FILEDES, TIOCSLTC, &ltc);
375 }
376 #endif /* UCB_NTTY */
377 #ifndef USG
378 #ifdef TIOCGETC
379 ioctl (FILEDES, TIOCGETC, &tbuf);
380 tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
381 tbuf.t_quitc = CHK (tbuf.t_quitc, CTRL ('\\'));
382 tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
383 tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
384 tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
385 /* brkc is left alone */
386 ioctl (FILEDES, TIOCSETC, &tbuf);
387 #endif /* TIOCGETC */
388 mode.sg_flags &= ~(RAW
389 #ifdef CBREAK
390 | CBREAK
391 #endif /* CBREAK */
392 | VTDELAY | ALLDELAY);
393 mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
394 #else /*USG */
395 ioctl (FILEDES, TCGETA, &mode);
396 mode.c_cc[VINTR] = CHK (mode.c_cc[VINTR], CTRL ('?'));
397 mode.c_cc[VQUIT] = CHK (mode.c_cc[VQUIT], CTRL ('\\'));
398 mode.c_cc[VEOF] = CHK (mode.c_cc[VEOF], CTRL ('D'));
399
400 mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF);
401 mode.c_iflag |= (BRKINT | ISTRIP | ICRNL | IXON);
402 mode.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |
403 NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
404 mode.c_oflag |= (OPOST | ONLCR);
405 mode.c_cflag &= ~(CSIZE | PARODD | CLOCAL);
406 #ifndef hp9000s800
407 mode.c_cflag |= (CS8 | CREAD);
408 #else /*hp9000s800 */
409 mode.c_cflag |= (CS8 | CSTOPB | CREAD);
410 #endif /* hp9000s800 */
411 mode.c_lflag &= ~(XCASE | ECHONL | NOFLSH);
412 mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOK);
413 ioctl (FILEDES, TCSETAW, &mode);
414 #endif /* USG */
415
416 return;
417 } /* _tuiReset */
418 #endif
419
420 void
421 tui_show_source (const char *file, int line)
422 {
423 /* make sure that the source window is displayed */
424 tuiAddWinToLayout (SRC_WIN);
425
426 tuiUpdateSourceWindowsWithLine (current_source_symtab, line);
427 tuiUpdateLocatorFilename (file);
428 }
429
430 void
431 tui_show_assembly (CORE_ADDR addr)
432 {
433 tuiAddWinToLayout (DISASSEM_WIN);
434 tuiUpdateSourceWindowsWithAddr (addr);
435 }
436
437 int
438 tui_is_window_visible (TuiWinType type)
439 {
440 if (tui_version == 0)
441 return 0;
442
443 if (winList[type] == 0)
444 return 0;
445
446 return winList[type]->generic.isVisible;
447 }
448
449 int
450 tui_get_command_dimension (int *width, int *height)
451 {
452 if (!tui_version || !m_winPtrNotNull (cmdWin))
453 {
454 return 0;
455 }
456
457 *width = cmdWin->generic.width;
458 *height = cmdWin->generic.height;
459 return 1;
460 }