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