#include "config.h"
#ifdef HAVE_NCURSES_H
#include <ncurses.h>
#else
#ifdef HAVE_CURSES_H
#include <curses.h>
#endif
#endif
#include <stdio.h>
#include "defs.h"
#include "terminal.h"
#include "target.h"
#include "event-loop.h"
#include "event-top.h"
#include "command.h"
#include "top.h"
#include "readline/readline.h"
#include "tui.h"
#include "tuiData.h"
#include "tuiIO.h"
#include "tuiCommand.h"
#include "tuiWin.h"
#include "tuiGeneralWin.h"
#include "tui-file.h"
#include "ui-out.h"
#include "cli-out.h"
#include <fcntl.h>
#include <signal.h>
#undef CTRL_CHAR
#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0))
#define TUI_USE_PIPE_FOR_READLINE
static struct ui_file *tui_stdout;
static struct ui_file *tui_stderr;
struct ui_out *tui_out;
static struct ui_file *tui_old_stdout;
static struct ui_file *tui_old_stderr;
struct ui_out *tui_old_uiout;
static Function *tui_old_rl_getc_function;
static VFunction *tui_old_rl_redisplay_function;
static VFunction *tui_old_rl_prep_terminal;
static VFunction *tui_old_rl_deprep_terminal;
static int tui_old_readline_echoing_p;
static FILE *tui_rl_outstream;
static FILE *tui_old_rl_outstream;
#ifdef TUI_USE_PIPE_FOR_READLINE
static int tui_readline_pipe[2];
#endif
static char *tui_rl_saved_prompt;
static unsigned int _tuiHandleResizeDuringIO (unsigned int);
static void
tui_putc (char c)
{
char buf[2];
buf[0] = c;
buf[1] = 0;
tui_puts (buf);
}
void
tui_puts (const char *string)
{
static int tui_skip_line = -1;
char c;
WINDOW *w;
w = cmdWin->generic.handle;
while ((c = *string++) != 0)
{
if (c == '\032')
{
tui_skip_line++;
}
else if (tui_skip_line != 1)
{
tui_skip_line = -1;
waddch (w, c);
}
else if (c == '\n')
tui_skip_line = -1;
}
getyx (w, cmdWin->detail.commandInfo.curLine,
cmdWin->detail.commandInfo.curch);
cmdWin->detail.commandInfo.start_line = cmdWin->detail.commandInfo.curLine;
wrefresh (w);
fflush (stdout);
}
void
tui_redisplay_readline (void)
{
int prev_col;
int height;
int col, line;
int c_pos;
int c_line;
int in;
WINDOW *w;
char *prompt;
int start_line;
if (tui_current_key_mode == tui_one_command_mode && rl_end == 0)
tui_set_key_mode (tui_single_key_mode);
if (tui_current_key_mode == tui_single_key_mode)
prompt = "";
else
prompt = tui_rl_saved_prompt;
c_pos = -1;
c_line = -1;
w = cmdWin->generic.handle;
start_line = cmdWin->detail.commandInfo.start_line;
wmove (w, start_line, 0);
prev_col = 0;
height = 1;
for (in = 0; prompt && prompt[in]; in++)
{
waddch (w, prompt[in]);
getyx (w, line, col);
if (col < prev_col)
height++;
prev_col = col;
}
for (in = 0; in < rl_end; in++)
{
unsigned char c;
c = (unsigned char) rl_line_buffer[in];
if (in == rl_point)
{
getyx (w, c_line, c_pos);
}
if (CTRL_CHAR (c) || c == RUBOUT)
{
waddch (w, '^');
waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?');
}
else
{
waddch (w, c);
}
if (c == '\n')
{
getyx (w, cmdWin->detail.commandInfo.start_line,
cmdWin->detail.commandInfo.curch);
}
getyx (w, line, col);
if (col < prev_col)
height++;
prev_col = col;
}
wclrtobot (w);
getyx (w, cmdWin->detail.commandInfo.start_line,
cmdWin->detail.commandInfo.curch);
if (c_line >= 0)
{
wmove (w, c_line, c_pos);
cmdWin->detail.commandInfo.curLine = c_line;
cmdWin->detail.commandInfo.curch = c_pos;
}
cmdWin->detail.commandInfo.start_line -= height - 1;
wrefresh (w);
fflush(stdout);
}
static void
tui_prep_terminal (void)
{
xfree (tui_rl_saved_prompt);
tui_rl_saved_prompt = xstrdup (rl_prompt);
}
static void
tui_deprep_terminal (void)
{
}
#ifdef TUI_USE_PIPE_FOR_READLINE
static void
tui_readline_output (int code, gdb_client_data data)
{
int size;
char buf[256];
size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1);
if (size > 0 && tui_active)
{
buf[size] = 0;
tui_puts (buf);
}
}
#endif
static char *
printable_part (pathname)
char *pathname;
{
char *temp;
temp = rl_filename_completion_desired ? strrchr (pathname, '/') : (char *)NULL;
#if defined (__MSDOS__)
if (rl_filename_completion_desired && temp == 0 && isalpha (pathname[0]) && pathname[1] == ':')
temp = pathname + 1;
#endif
return (temp ? ++temp : pathname);
}
#define PUTX(c) \
do { \
if (CTRL_CHAR (c)) \
{ \
tui_puts ("^"); \
tui_putc (UNCTRL (c)); \
printed_len += 2; \
} \
else if (c == RUBOUT) \
{ \
tui_puts ("^?"); \
printed_len += 2; \
} \
else \
{ \
tui_putc (c); \
printed_len++; \
} \
} while (0)
static int
print_filename (to_print, full_pathname)
char *to_print, *full_pathname;
{
int printed_len = 0;
char *s;
for (s = to_print; *s; s++)
{
PUTX (*s);
}
return printed_len;
}
static int
get_y_or_n ()
{
extern int _rl_abort_internal ();
int c;
for (;;)
{
c = rl_read_key ();
if (c == 'y' || c == 'Y' || c == ' ')
return (1);
if (c == 'n' || c == 'N' || c == RUBOUT)
return (0);
if (c == ABORT_CHAR)
_rl_abort_internal ();
beep ();
}
}
static void
tui_rl_display_match_list (matches, len, max)
char **matches;
int len, max;
{
typedef int QSFUNC (const void *, const void *);
extern int _rl_qsort_string_compare (const void*, const void*);
extern int _rl_print_completions_horizontally;
int count, limit, printed_len;
int i, j, k, l;
char *temp;
int screenwidth = cmdWin->generic.width;
if (len >= rl_completion_query_items)
{
char msg[256];
sprintf (msg, "\nDisplay all %d possibilities? (y or n)", len);
tui_puts (msg);
if (get_y_or_n () == 0)
{
tui_puts ("\n");
return;
}
}
max += 2;
limit = screenwidth / max;
if (limit != 1 && (limit * max == screenwidth))
limit--;
if (limit == 0)
limit = 1;
count = (len + (limit - 1)) / limit;
if (rl_ignore_completion_duplicates == 0)
qsort (matches + 1, len, sizeof (char *),
(QSFUNC *)_rl_qsort_string_compare);
tui_putc ('\n');
if (_rl_print_completions_horizontally == 0)
{
for (i = 1; i <= count; i++)
{
for (j = 0, l = i; j < limit; j++)
{
if (l > len || matches[l] == 0)
break;
else
{
temp = printable_part (matches[l]);
printed_len = print_filename (temp, matches[l]);
if (j + 1 < limit)
for (k = 0; k < max - printed_len; k++)
tui_putc (' ');
}
l += count;
}
tui_putc ('\n');
}
}
else
{
for (i = 1; matches[i]; i++)
{
temp = printable_part (matches[i]);
printed_len = print_filename (temp, matches[i]);
if (matches[i+1])
{
if (i && (limit > 1) && (i % limit) == 0)
tui_putc ('\n');
else
for (k = 0; k < max - printed_len; k++)
tui_putc (' ');
}
}
tui_putc ('\n');
}
}
void
tui_setup_io (int mode)
{
extern int readline_echoing_p;
if (mode)
{
tui_old_rl_redisplay_function = rl_redisplay_function;
tui_old_rl_deprep_terminal = rl_deprep_term_function;
tui_old_rl_prep_terminal = rl_prep_term_function;
tui_old_rl_getc_function = rl_getc_function;
tui_old_rl_outstream = rl_outstream;
tui_old_readline_echoing_p = readline_echoing_p;
rl_redisplay_function = tui_redisplay_readline;
rl_deprep_term_function = tui_deprep_terminal;
rl_prep_term_function = tui_prep_terminal;
rl_getc_function = tui_getc;
readline_echoing_p = 0;
rl_outstream = tui_rl_outstream;
rl_prompt = 0;
rl_completion_display_matches_hook = tui_rl_display_match_list;
rl_already_prompted = 0;
tui_old_stdout = gdb_stdout;
tui_old_stderr = gdb_stderr;
tui_old_uiout = uiout;
gdb_stdout = tui_stdout;
gdb_stderr = tui_stderr;
gdb_stdlog = gdb_stdout;
gdb_stdtarg = gdb_stderr;
uiout = tui_out;
savetty ();
}
else
{
gdb_stdout = tui_old_stdout;
gdb_stderr = tui_old_stderr;
gdb_stdlog = gdb_stdout;
gdb_stdtarg = gdb_stderr;
uiout = tui_old_uiout;
rl_redisplay_function = tui_old_rl_redisplay_function;
rl_deprep_term_function = tui_old_rl_deprep_terminal;
rl_prep_term_function = tui_old_rl_prep_terminal;
rl_getc_function = tui_old_rl_getc_function;
rl_outstream = tui_old_rl_outstream;
rl_completion_display_matches_hook = 0;
readline_echoing_p = tui_old_readline_echoing_p;
rl_already_prompted = 0;
savetty ();
}
}
#ifdef SIGCONT
static void
tui_cont_sig (int sig)
{
if (tui_active)
{
resetty ();
tuiRefreshAll ();
wmove (cmdWin->generic.handle,
cmdWin->detail.commandInfo.start_line,
cmdWin->detail.commandInfo.curch);
wrefresh (cmdWin->generic.handle);
}
signal (sig, tui_cont_sig);
}
#endif
void
tui_initialize_io ()
{
#ifdef SIGCONT
signal (SIGCONT, tui_cont_sig);
#endif
tui_stdout = tui_fileopen (stdout);
tui_stderr = tui_fileopen (stderr);
tui_out = tui_out_new (tui_stdout);
tui_old_uiout = uiout = cli_out_new (gdb_stdout);
#ifdef TUI_USE_PIPE_FOR_READLINE
if (pipe (tui_readline_pipe) != 0)
{
fprintf_unfiltered (gdb_stderr, "Cannot create pipe for readline");
exit (1);
}
tui_rl_outstream = fdopen (tui_readline_pipe[1], "w");
if (tui_rl_outstream == 0)
{
fprintf_unfiltered (gdb_stderr, "Cannot redirect readline output");
exit (1);
}
setvbuf (tui_rl_outstream, (char*) NULL, _IOLBF, 0);
#ifdef O_NONBLOCK
(void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK);
#else
#ifdef O_NDELAY
(void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY);
#endif
#endif
add_file_handler (tui_readline_pipe[0], tui_readline_output, 0);
#else
tui_rl_outstream = stdout;
#endif
}
int
tui_getc (FILE *fp)
{
int ch;
WINDOW *w;
w = cmdWin->generic.handle;
#ifdef TUI_USE_PIPE_FOR_READLINE
tui_readline_output (GDB_READABLE, 0);
#endif
ch = wgetch (w);
ch = _tuiHandleResizeDuringIO (ch);
if (ch == '\n')
{
if (rl_end == 0)
{
wmove (w, cmdWin->detail.commandInfo.curLine, 0);
wclrtoeol (w);
wrefresh (w);
napms (20);
}
else
{
wmove (w, cmdWin->detail.commandInfo.curLine,
cmdWin->detail.commandInfo.curch);
waddch (w, ch);
}
}
if (m_isCommandChar (ch))
{
ch = tuiDispatchCtrlChar (ch);
}
if (ch == '\n' || ch == '\r' || ch == '\f')
cmdWin->detail.commandInfo.curch = 0;
#if 0
else
tuiIncrCommandCharCountBy (1);
#endif
if (ch == KEY_BACKSPACE)
return '\b';
return ch;
}
static unsigned int
_tuiHandleResizeDuringIO (unsigned int originalCh)
{
if (tuiWinResized ())
{
tuiRefreshAll ();
dont_repeat ();
tuiSetWinResizedTo (FALSE);
return '\n';
}
else
return originalCh;
}