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