#include "info.h"
#include "terminal.h"
#include "termdep.h"
#include <sys/types.h>
#include <signal.h>
#ifdef HAVE_NCURSES_TERMCAP_H
#include <ncurses/termcap.h>
#else
#ifdef HAVE_TERMCAP_H
#include <termcap.h>
#else
#undef PC
char *BC, *UP;
char PC;
short ospeed;
extern int tgetnum (), tgetflag (), tgetent ();
extern char *tgetstr (), *tgoto ();
extern void tputs ();
#endif
#endif
VFunction *terminal_begin_inverse_hook = (VFunction *)NULL;
VFunction *terminal_end_inverse_hook = (VFunction *)NULL;
VFunction *terminal_prep_terminal_hook = (VFunction *)NULL;
VFunction *terminal_unprep_terminal_hook = (VFunction *)NULL;
VFunction *terminal_up_line_hook = (VFunction *)NULL;
VFunction *terminal_down_line_hook = (VFunction *)NULL;
VFunction *terminal_clear_screen_hook = (VFunction *)NULL;
VFunction *terminal_clear_to_eol_hook = (VFunction *)NULL;
VFunction *terminal_get_screen_size_hook = (VFunction *)NULL;
VFunction *terminal_goto_xy_hook = (VFunction *)NULL;
VFunction *terminal_initialize_terminal_hook = (VFunction *)NULL;
VFunction *terminal_new_terminal_hook = (VFunction *)NULL;
VFunction *terminal_put_text_hook = (VFunction *)NULL;
VFunction *terminal_ring_bell_hook = (VFunction *)NULL;
VFunction *terminal_write_chars_hook = (VFunction *)NULL;
VFunction *terminal_scroll_terminal_hook = (VFunction *)NULL;
static char *term_buffer = (char *)NULL;
static char *term_string_buffer = (char *)NULL;
static char *term_goto, *term_clreol, *term_cr, *term_clrpag;
static char *term_begin_use, *term_end_use;
static char *term_AL, *term_DL, *term_al, *term_dl;
static char *term_keypad_on, *term_keypad_off;
static char *term_up;
static char *term_dn;
static char *audible_bell;
static char *visible_bell;
static char *term_mm;
static char *term_mo;
static char *term_invbeg;
static char *term_invend;
static int
output_character_function (c)
int c;
{
putc (c, stdout);
return c;
}
#define send_to_terminal(string) \
do { \
if (string) \
tputs (string, 1, output_character_function); \
} while (0)
static void
terminal_begin_using_terminal ()
{
RETSIGTYPE (*sigsave) ();
if (term_keypad_on)
send_to_terminal (term_keypad_on);
if (!term_begin_use || !*term_begin_use)
return;
#ifdef SIGWINCH
sigsave = signal (SIGWINCH, SIG_IGN);
#endif
send_to_terminal (term_begin_use);
fflush (stdout);
sleep (1);
#ifdef SIGWINCH
signal (SIGWINCH, sigsave);
#endif
}
static void
terminal_end_using_terminal ()
{
RETSIGTYPE (*sigsave) ();
if (term_keypad_off)
send_to_terminal (term_keypad_off);
if (!term_end_use || !*term_end_use)
return;
#ifdef SIGWINCH
sigsave = signal (SIGWINCH, SIG_IGN);
#endif
send_to_terminal (term_end_use);
fflush (stdout);
sleep (1);
#ifdef SIGWINCH
signal (SIGWINCH, sigsave);
#endif
}
int screenwidth, screenheight;
int terminal_is_dumb_p = 0;
int terminal_has_meta_p = 0;
int terminal_has_visible_bell_p = 0;
int terminal_use_visible_bell_p = 0;
int terminal_can_scroll = 0;
char *term_ku = (char *)NULL;
char *term_kd = (char *)NULL;
char *term_kr = (char *)NULL;
char *term_kl = (char *)NULL;
char *term_kP = (char *)NULL;
char *term_kN = (char *)NULL;
void
terminal_goto_xy (x, y)
int x, y;
{
if (terminal_goto_xy_hook)
(*terminal_goto_xy_hook) (x, y);
else
{
if (term_goto)
tputs (tgoto (term_goto, x, y), 1, output_character_function);
}
}
void
terminal_put_text (string)
char *string;
{
if (terminal_put_text_hook)
(*terminal_put_text_hook) (string);
else
{
printf ("%s", string);
}
}
void
terminal_write_chars (string, nchars)
char *string;
int nchars;
{
if (terminal_write_chars_hook)
(*terminal_write_chars_hook) (string, nchars);
else
{
if (nchars)
fwrite (string, 1, nchars, stdout);
}
}
void
terminal_clear_to_eol ()
{
if (terminal_clear_to_eol_hook)
(*terminal_clear_to_eol_hook) ();
else
{
send_to_terminal (term_clreol);
}
}
void
terminal_clear_screen ()
{
if (terminal_clear_screen_hook)
(*terminal_clear_screen_hook) ();
else
{
send_to_terminal (term_clrpag);
}
}
void
terminal_up_line ()
{
if (terminal_up_line_hook)
(*terminal_up_line_hook) ();
else
{
send_to_terminal (term_up);
}
}
void
terminal_down_line ()
{
if (terminal_down_line_hook)
(*terminal_down_line_hook) ();
else
{
send_to_terminal (term_dn);
}
}
void
terminal_begin_inverse ()
{
if (terminal_begin_inverse_hook)
(*terminal_begin_inverse_hook) ();
else
{
send_to_terminal (term_invbeg);
}
}
void
terminal_end_inverse ()
{
if (terminal_end_inverse_hook)
(*terminal_end_inverse_hook) ();
else
{
send_to_terminal (term_invend);
}
}
void
terminal_ring_bell ()
{
if (terminal_ring_bell_hook)
(*terminal_ring_bell_hook) ();
else
{
if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
send_to_terminal (visible_bell);
else
send_to_terminal (audible_bell);
}
}
static void
terminal_delete_lines (start, count)
int start, count;
{
int lines;
if (start < 0)
start = 0;
lines = screenheight - start;
terminal_goto_xy (0, start);
if (term_DL)
tputs (tgoto (term_DL, 0, count), lines, output_character_function);
else
{
while (count--)
tputs (term_dl, lines, output_character_function);
}
fflush (stdout);
}
static void
terminal_insert_lines (start, count)
int start, count;
{
int lines;
if (start < 0)
start = 0;
lines = screenheight - start;
terminal_goto_xy (0, start);
if (term_AL)
tputs (tgoto (term_AL, 0, count), lines, output_character_function);
else
{
while (count--)
tputs (term_al, lines, output_character_function);
}
fflush (stdout);
}
void
terminal_scroll_terminal (start, end, amount)
int start, end, amount;
{
if (!terminal_can_scroll)
return;
if (amount == 0)
return;
if (terminal_scroll_terminal_hook)
(*terminal_scroll_terminal_hook) (start, end, amount);
else
{
if (amount > 0)
{
terminal_delete_lines (end, amount);
terminal_insert_lines (start, amount);
}
if (amount < 0)
{
int abs_amount = -amount;
terminal_delete_lines (start - abs_amount, abs_amount);
terminal_insert_lines (end - abs_amount, abs_amount);
}
}
}
void
terminal_new_terminal (terminal_name)
char *terminal_name;
{
if (terminal_new_terminal_hook)
(*terminal_new_terminal_hook) (terminal_name);
else
{
terminal_initialize_terminal (terminal_name);
}
}
void
terminal_get_screen_size ()
{
if (terminal_get_screen_size_hook)
(*terminal_get_screen_size_hook) ();
else
{
screenwidth = screenheight = 0;
#if defined (TIOCGWINSZ)
{
struct winsize window_size;
if (ioctl (fileno (stdout), TIOCGWINSZ, &window_size) == 0)
{
screenwidth = (int) window_size.ws_col;
screenheight = (int) window_size.ws_row;
}
}
#endif
if (screenwidth <= 0)
{
char *sw = getenv ("COLUMNS");
if (sw)
screenwidth = atoi (sw);
if (screenwidth <= 0)
screenwidth = tgetnum ("co");
}
if (screenheight <= 0)
{
char *sh = getenv ("LINES");
if (sh)
screenheight = atoi (sh);
if (screenheight <= 0)
screenheight = tgetnum ("li");
}
if (screenwidth <= 0)
screenwidth = 80;
if (screenheight <= 0)
screenheight = 24;
}
}
void
terminal_initialize_terminal (terminal_name)
char *terminal_name;
{
char *term, *buffer;
terminal_is_dumb_p = 0;
if (terminal_initialize_terminal_hook)
{
(*terminal_initialize_terminal_hook) (terminal_name);
return;
}
term = terminal_name ? terminal_name : getenv ("TERM");
if (!term_string_buffer)
term_string_buffer = (char *)xmalloc (2048);
if (!term_buffer)
term_buffer = (char *)xmalloc (2048);
buffer = term_string_buffer;
term_clrpag = term_cr = term_clreol = (char *)NULL;
if (!term)
term = "dumb";
if (tgetent (term_buffer, term) <= 0)
{
terminal_is_dumb_p = 1;
screenwidth = 80;
screenheight = 24;
term_cr = "\r";
term_up = term_dn = audible_bell = visible_bell = (char *)NULL;
term_ku = term_kd = term_kl = term_kr = (char *)NULL;
term_kP = term_kN = (char *)NULL;
return;
}
BC = tgetstr ("pc", &buffer);
PC = BC ? *BC : 0;
#if defined (TIOCGETP)
{
struct sgttyb sg;
if (ioctl (fileno (stdout), TIOCGETP, &sg) != -1)
ospeed = sg.sg_ospeed;
else
ospeed = B9600;
}
#else
ospeed = B9600;
#endif
term_cr = tgetstr ("cr", &buffer);
term_clreol = tgetstr ("ce", &buffer);
term_clrpag = tgetstr ("cl", &buffer);
term_goto = tgetstr ("cm", &buffer);
term_AL = tgetstr ("AL", &buffer);
term_DL = tgetstr ("DL", &buffer);
term_al = tgetstr ("al", &buffer);
term_dl = tgetstr ("dl", &buffer);
terminal_can_scroll = ((term_AL || term_al) && (term_DL || term_dl));
term_invbeg = tgetstr ("mr", &buffer);
if (term_invbeg)
term_invend = tgetstr ("me", &buffer);
else
term_invend = (char *)NULL;
if (!term_cr)
term_cr = "\r";
terminal_get_screen_size ();
term_up = tgetstr ("up", &buffer);
term_dn = tgetstr ("dn", &buffer);
visible_bell = tgetstr ("vb", &buffer);
terminal_has_visible_bell_p = (visible_bell != (char *)NULL);
audible_bell = tgetstr ("bl", &buffer);
if (!audible_bell)
audible_bell = "\007";
term_begin_use = tgetstr ("ti", &buffer);
term_end_use = tgetstr ("te", &buffer);
term_keypad_on = tgetstr ("ks", &buffer);
term_keypad_off = tgetstr ("ke", &buffer);
terminal_has_meta_p = (tgetflag ("km") || tgetflag ("MT"));
if (terminal_has_meta_p)
{
term_mm = tgetstr ("mm", &buffer);
term_mo = tgetstr ("mo", &buffer);
}
else
{
term_mm = (char *)NULL;
term_mo = (char *)NULL;
}
term_ku = tgetstr ("ku", &buffer);
term_kd = tgetstr ("kd", &buffer);
term_kr = tgetstr ("kr", &buffer);
term_kl = tgetstr ("kl", &buffer);
term_kP = tgetstr ("kP", &buffer);
term_kN = tgetstr ("kN", &buffer);
if (!term_goto)
terminal_is_dumb_p = 1;
}
#if defined (TIOCGETC)
struct tchars original_tchars;
#endif
#if defined (TIOCGLTC)
struct ltchars original_ltchars;
#endif
#if defined (HAVE_TERMIOS_H)
struct termios original_termios, ttybuff;
#else
# if defined (HAVE_TERMIO_H)
struct termio original_termio, ttybuff;
# else
int original_tty_flags = 0;
int original_lmode;
struct sgttyb ttybuff;
# endif
#endif
void
terminal_prep_terminal ()
{
int tty;
if (terminal_prep_terminal_hook)
{
(*terminal_prep_terminal_hook) ();
return;
}
terminal_begin_using_terminal ();
tty = fileno (stdin);
#if defined (HAVE_TERMIOS_H)
tcgetattr (tty, &original_termios);
tcgetattr (tty, &ttybuff);
#else
# if defined (HAVE_TERMIO_H)
ioctl (tty, TCGETA, &original_termio);
ioctl (tty, TCGETA, &ttybuff);
# endif
#endif
#if defined (HAVE_TERMIOS_H) || defined (HAVE_TERMIO_H)
ttybuff.c_iflag &= (~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL & ~IXON);
#ifdef ONLCR
ttybuff.c_oflag &= ~ONLCR ;
#endif
#ifdef OCRNL
ttybuff.c_oflag &= ~OCRNL;
#endif
ttybuff.c_lflag &= (~ICANON & ~ECHO);
ttybuff.c_cc[VMIN] = 1;
ttybuff.c_cc[VTIME] = 0;
if (ttybuff.c_cc[VINTR] == '\177')
ttybuff.c_cc[VINTR] = -1;
if (ttybuff.c_cc[VQUIT] == '\177')
ttybuff.c_cc[VQUIT] = -1;
#ifdef VLNEXT
if (ttybuff.c_cc[VLNEXT] == '\026')
ttybuff.c_cc[VLNEXT] = -1;
#endif
#endif
#if defined (HAVE_TERMIOS_H)
tcsetattr (tty, TCSANOW, &ttybuff);
#else
# if defined (HAVE_TERMIO_H)
ioctl (tty, TCSETA, &ttybuff);
# endif
#endif
#if !defined (HAVE_TERMIOS_H) && !defined (HAVE_TERMIO_H)
ioctl (tty, TIOCGETP, &ttybuff);
if (!original_tty_flags)
original_tty_flags = ttybuff.sg_flags;
# if defined (PASS8)
ttybuff.sg_flags |= PASS8;
# endif
# if defined (TIOCLGET) && defined (LPASS8)
{
int flags;
ioctl (tty, TIOCLGET, &flags);
original_lmode = flags;
flags |= LPASS8;
ioctl (tty, TIOCLSET, &flags);
}
# endif
# if defined (TIOCGETC)
{
struct tchars temp;
ioctl (tty, TIOCGETC, &original_tchars);
temp = original_tchars;
temp.t_startc = temp.t_stopc = -1;
temp.t_eofc = -1;
if (temp.t_intrc == '\177')
temp.t_intrc = -1;
if (temp.t_quitc == '\177')
temp.t_quitc = -1;
ioctl (tty, TIOCSETC, &temp);
}
# endif
# if defined (TIOCGLTC)
{
struct ltchars temp;
ioctl (tty, TIOCGLTC, &original_ltchars);
temp = original_ltchars;
temp.t_lnextc = -1;
temp.t_dsuspc = -1;
temp.t_flushc = -1;
ioctl (tty, TIOCSLTC, &temp);
}
# endif
ttybuff.sg_flags &= ~ECHO;
ttybuff.sg_flags |= CBREAK;
ioctl (tty, TIOCSETN, &ttybuff);
#endif
}
void
terminal_unprep_terminal ()
{
int tty;
if (terminal_unprep_terminal_hook)
{
(*terminal_unprep_terminal_hook) ();
return;
}
tty = fileno (stdin);
#if defined (HAVE_TERMIOS_H)
tcsetattr (tty, TCSANOW, &original_termios);
#else
# if defined (HAVE_TERMIO_H)
ioctl (tty, TCSETA, &original_termio);
# else
ioctl (tty, TIOCGETP, &ttybuff);
ttybuff.sg_flags = original_tty_flags;
ioctl (tty, TIOCSETN, &ttybuff);
# if defined (TIOCGETC)
ioctl (tty, TIOCSETC, &original_tchars);
# endif
# if defined (TIOCGLTC)
ioctl (tty, TIOCSLTC, &original_ltchars);
# endif
# if defined (TIOCLGET) && defined (LPASS8)
ioctl (tty, TIOCLSET, &original_lmode);
# endif
# endif
#endif
terminal_end_using_terminal ();
}