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