]> Git Repo - binutils.git/blob - gdb/tui/tuiIO.c
2002-08-31 Stephane Carrez <[email protected]>
[binutils.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.049633 seconds and 4 git commands to generate.