]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tuiIO.c
31e7c23ad2be9cc2a3ba916dac601b72ba6d8071
[thirdparty/binutils-gdb.git] / gdb / tui / tuiIO.c
1 /* TUI support I/O functions.
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 "defs.h"
34 #include "terminal.h"
35 #include "target.h"
36 #include "event-loop.h"
37 #include "command.h"
38 #include "top.h"
39 #include "readline/readline.h"
40 #include "tui.h"
41 #include "tuiData.h"
42 #include "tuiIO.h"
43 #include "tuiCommand.h"
44 #include "tuiWin.h"
45 #include "tuiGeneralWin.h"
46 #include "tui-file.h"
47 #include "ui-out.h"
48 #include "cli-out.h"
49 #include <fcntl.h>
50 #include <signal.h>
51
52 /* This file controls the IO interactions between gdb and curses.
53 When the TUI is enabled, gdb has two modes a curses and a standard
54 mode.
55
56 In curses mode, the gdb outputs are made in a curses command window.
57 For this, the gdb_stdout and gdb_stderr are redirected to the specific
58 ui_file implemented by TUI. The output is handled by tui_puts().
59 The input is also controlled by curses with tui_getc(). The readline
60 library uses this function to get its input. Several readline hooks
61 are installed to redirect readline output to the TUI (see also the
62 note below).
63
64 In normal mode, the gdb outputs are restored to their origin, that
65 is as if TUI is not used. Readline also uses its original getc()
66 function with stdin.
67
68 Note: the current readline is not clean in its management of the output.
69 Even if we install a redisplay handler, it sometimes writes on a stdout
70 file. It is important to redirect every output produced by readline,
71 otherwise the curses window will be garbled. This is implemented with
72 a pipe that TUI reads and readline writes to. A gdb input handler
73 is created so that reading the pipe is handled automatically.
74 This will probably not work on non-Unix platforms. The best fix is
75 to make readline clean enougth so that is never write on stdout. */
76
77 /* TUI output files. */
78 static struct ui_file *tui_stdout;
79 static struct ui_file *tui_stderr;
80 static struct ui_out *tui_out;
81
82 /* GDB output files in non-curses mode. */
83 static struct ui_file *tui_old_stdout;
84 static struct ui_file *tui_old_stderr;
85 static struct ui_out *tui_old_uiout;
86
87 /* Readline previous hooks. */
88 static Function *tui_old_rl_getc_function;
89 static VFunction *tui_old_rl_redisplay_function;
90 static VFunction *tui_old_rl_prep_terminal;
91 static VFunction *tui_old_rl_deprep_terminal;
92 static int tui_old_readline_echoing_p;
93
94 /* Readline output stream.
95 Should be removed when readline is clean. */
96 static FILE *tui_rl_outstream;
97 static FILE *tui_old_rl_outstream;
98 static int tui_readline_pipe[2];
99
100 static unsigned int _tuiHandleResizeDuringIO (unsigned int);
101
102
103 /* Print the string in the curses command window. */
104 void
105 tui_puts (const char *string)
106 {
107 static int tui_skip_line = -1;
108 char c;
109 WINDOW *w;
110
111 w = cmdWin->generic.handle;
112 while ((c = *string++) != 0)
113 {
114 /* Catch annotation and discard them. We need two \032 and
115 discard until a \n is seen. */
116 if (c == '\032')
117 {
118 tui_skip_line++;
119 }
120 else if (tui_skip_line != 1)
121 {
122 tui_skip_line = -1;
123 waddch (w, c);
124 }
125 else if (c == '\n')
126 tui_skip_line = -1;
127 }
128 getyx (w, cmdWin->detail.commandInfo.curLine,
129 cmdWin->detail.commandInfo.curch);
130 cmdWin->detail.commandInfo.start_line = cmdWin->detail.commandInfo.curLine;
131
132 /* We could defer the following. */
133 wrefresh (w);
134 fflush (stdout);
135 }
136
137 /* Readline callback.
138 Redisplay the command line with its prompt after readline has
139 changed the edited text. */
140 static void
141 tui_redisplay_readline (void)
142 {
143 int prev_col;
144 int height;
145 int col, line;
146 int c_pos;
147 int c_line;
148 int in;
149 WINDOW *w;
150 char *prompt;
151 int start_line;
152
153 prompt = get_prompt ();
154
155 c_pos = -1;
156 c_line = -1;
157 w = cmdWin->generic.handle;
158 start_line = cmdWin->detail.commandInfo.start_line;
159 wmove (w, start_line, 0);
160 prev_col = 0;
161 height = 1;
162 for (in = 0; prompt && prompt[in]; in++)
163 {
164 waddch (w, prompt[in]);
165 getyx (w, line, col);
166 if (col < prev_col)
167 height++;
168 prev_col = col;
169 }
170 for (in = 0; in < rl_end; in++)
171 {
172 unsigned char c;
173
174 c = (unsigned char) rl_line_buffer[in];
175 if (in == rl_point)
176 {
177 getyx (w, c_line, c_pos);
178 }
179
180 if (CTRL_CHAR (c) || c == RUBOUT)
181 {
182 waddch (w, '^');
183 waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?');
184 }
185 else
186 {
187 waddch (w, c);
188 }
189 if (c == '\n')
190 {
191 getyx (w, cmdWin->detail.commandInfo.start_line,
192 cmdWin->detail.commandInfo.curch);
193 }
194 getyx (w, line, col);
195 if (col < prev_col)
196 height++;
197 prev_col = col;
198 }
199 wclrtobot (w);
200 getyx (w, cmdWin->detail.commandInfo.start_line,
201 cmdWin->detail.commandInfo.curch);
202 if (c_line >= 0)
203 {
204 wmove (w, c_line, c_pos);
205 cmdWin->detail.commandInfo.curLine = c_line;
206 cmdWin->detail.commandInfo.curch = c_pos;
207 }
208 cmdWin->detail.commandInfo.start_line -= height - 1;
209
210 wrefresh (w);
211 fflush(stdout);
212 }
213
214 /* Readline callback to prepare the terminal. It is called once
215 each time we enter readline. There is nothing to do in curses mode. */
216 static void
217 tui_prep_terminal (void)
218 {
219 }
220
221 /* Readline callback to restore the terminal. It is called once
222 each time we leave readline. There is nothing to do in curses mode. */
223 static void
224 tui_deprep_terminal (void)
225 {
226 }
227
228 /* Read readline output pipe and feed the command window with it.
229 Should be removed when readline is clean. */
230 static void
231 tui_readline_output (int code, gdb_client_data data)
232 {
233 int size;
234 char buf[256];
235
236 size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1);
237 if (size > 0 && tui_active)
238 {
239 buf[size] = 0;
240 tui_puts (buf);
241 }
242 }
243
244 /* Setup the IO for curses or non-curses mode.
245 - In non-curses mode, readline and gdb use the standard input and
246 standard output/error directly.
247 - In curses mode, the standard output/error is controlled by TUI
248 with the tui_stdout and tui_stderr. The output is redirected in
249 the curses command window. Several readline callbacks are installed
250 so that readline asks for its input to the curses command window
251 with wgetch(). */
252 void
253 tui_setup_io (int mode)
254 {
255 extern int readline_echoing_p;
256
257 if (mode)
258 {
259 /* Redirect readline to TUI. */
260 tui_old_rl_redisplay_function = rl_redisplay_function;
261 tui_old_rl_deprep_terminal = rl_deprep_term_function;
262 tui_old_rl_prep_terminal = rl_prep_term_function;
263 tui_old_rl_getc_function = rl_getc_function;
264 tui_old_rl_outstream = rl_outstream;
265 tui_old_readline_echoing_p = readline_echoing_p;
266 rl_redisplay_function = tui_redisplay_readline;
267 rl_deprep_term_function = tui_deprep_terminal;
268 rl_prep_term_function = tui_prep_terminal;
269 rl_getc_function = tui_getc;
270 readline_echoing_p = 0;
271 rl_outstream = tui_rl_outstream;
272 rl_prompt = 0;
273
274 /* Keep track of previous gdb output. */
275 tui_old_stdout = gdb_stdout;
276 tui_old_stderr = gdb_stderr;
277 tui_old_uiout = uiout;
278
279 /* Reconfigure gdb output. */
280 gdb_stdout = tui_stdout;
281 gdb_stderr = tui_stderr;
282 gdb_stdlog = gdb_stdout; /* for moment */
283 gdb_stdtarg = gdb_stderr; /* for moment */
284 uiout = tui_out;
285
286 /* Save tty for SIGCONT. */
287 savetty ();
288 }
289 else
290 {
291 /* Restore gdb output. */
292 gdb_stdout = tui_old_stdout;
293 gdb_stderr = tui_old_stderr;
294 gdb_stdlog = gdb_stdout; /* for moment */
295 gdb_stdtarg = gdb_stderr; /* for moment */
296 uiout = tui_old_uiout;
297
298 /* Restore readline. */
299 rl_redisplay_function = tui_old_rl_redisplay_function;
300 rl_deprep_term_function = tui_old_rl_deprep_terminal;
301 rl_prep_term_function = tui_old_rl_prep_terminal;
302 rl_getc_function = tui_old_rl_getc_function;
303 rl_outstream = tui_old_rl_outstream;
304 readline_echoing_p = tui_old_readline_echoing_p;
305
306 /* Save tty for SIGCONT. */
307 savetty ();
308 }
309 }
310
311 #ifdef SIGCONT
312 /* Catch SIGCONT to restore the terminal and refresh the screen. */
313 static void
314 tui_cont_sig (int sig)
315 {
316 if (tui_active)
317 {
318 /* Restore the terminal setting because another process (shell)
319 might have changed it. */
320 resetty ();
321
322 /* Force a refresh of the screen. */
323 tuiRefreshAll ();
324
325 /* Update cursor position on the screen. */
326 wmove (cmdWin->generic.handle,
327 cmdWin->detail.commandInfo.start_line,
328 cmdWin->detail.commandInfo.curch);
329 wrefresh (cmdWin->generic.handle);
330 }
331 signal (sig, tui_cont_sig);
332 }
333 #endif
334
335 /* Initialize the IO for gdb in curses mode. */
336 void
337 tui_initialize_io ()
338 {
339 #ifdef SIGCONT
340 signal (SIGCONT, tui_cont_sig);
341 #endif
342
343 /* Create tui output streams. */
344 tui_stdout = tui_fileopen (stdout);
345 tui_stderr = tui_fileopen (stderr);
346 tui_out = tui_out_new (tui_stdout);
347
348 /* Create the default UI. It is not created because we installed
349 a init_ui_hook. */
350 uiout = cli_out_new (gdb_stdout);
351
352 /* Temporary solution for readline writing to stdout:
353 redirect readline output in a pipe, read that pipe and
354 output the content in the curses command window. */
355 if (pipe (tui_readline_pipe) != 0)
356 {
357 fprintf_unfiltered (gdb_stderr, "Cannot create pipe for readline");
358 exit (1);
359 }
360 tui_rl_outstream = fdopen (tui_readline_pipe[1], "w");
361 if (tui_rl_outstream == 0)
362 {
363 fprintf_unfiltered (gdb_stderr, "Cannot redirect readline output");
364 exit (1);
365 }
366 setlinebuf (tui_rl_outstream);
367
368 #ifdef O_NONBLOCK
369 (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK);
370 #else
371 #ifdef O_NDELAY
372 (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY);
373 #endif
374 #endif
375
376 add_file_handler (tui_readline_pipe[0], tui_readline_output, 0);
377 }
378
379 /* Get a character from the command window. This is called from the readline
380 package. */
381 int
382 tui_getc (FILE *fp)
383 {
384 int ch;
385 WINDOW *w;
386
387 w = cmdWin->generic.handle;
388
389 /* Flush readline output. */
390 tui_readline_output (GDB_READABLE, 0);
391
392 ch = wgetch (w);
393 ch = _tuiHandleResizeDuringIO (ch);
394
395 /* The \n must be echoed because it will not be printed by readline. */
396 if (ch == '\n')
397 {
398 /* When hitting return with an empty input, gdb executes the last
399 command. If we emit a newline, this fills up the command window
400 with empty lines with gdb prompt at beginning. Instead of that,
401 stay on the same line but provide a visual effect to show the
402 user we recognized the command. */
403 if (rl_end == 0)
404 {
405 wmove (w, cmdWin->detail.commandInfo.curLine, 0);
406
407 /* Clear the line. This will blink the gdb prompt since
408 it will be redrawn at the same line. */
409 wclrtoeol (w);
410 wrefresh (w);
411 napms (20);
412 }
413 else
414 {
415 wmove (w, cmdWin->detail.commandInfo.curLine,
416 cmdWin->detail.commandInfo.curch);
417 waddch (w, ch);
418 }
419 }
420
421 if (m_isCommandChar (ch))
422 { /* Handle prev/next/up/down here */
423 ch = tuiDispatchCtrlChar (ch);
424 }
425
426 if (ch == '\n' || ch == '\r' || ch == '\f')
427 cmdWin->detail.commandInfo.curch = 0;
428 #if 0
429 else
430 tuiIncrCommandCharCountBy (1);
431 #endif
432 if (ch == KEY_BACKSPACE)
433 return '\b';
434
435 return ch;
436 }
437
438
439 /* Cleanup when a resize has occured.
440 Returns the character that must be processed. */
441 static unsigned int
442 _tuiHandleResizeDuringIO (unsigned int originalCh)
443 {
444 if (tuiWinResized ())
445 {
446 tuiRefreshAll ();
447 dont_repeat ();
448 tuiSetWinResizedTo (FALSE);
449 return '\n';
450 }
451 else
452 return originalCh;
453 }