/*
* shtty.c -- abstract interface to the terminal, focusing on capabilities.
*/
/* Copyright (C) 1999 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see .
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#include
#include
static TTYSTRUCT ttin, ttout;
static int ttsaved = 0;
void
shttyvariables_strvec_to_string (vec, buffer, sep)
char** vec;
char* buffer;
char sep;
{
char* p;
char** it;
int i = 0;
size_t l = 0;
p = vec[0];
if (p)
{
i = strlen (p);
memcpy (buffer, p, i);
for (it = vec + 1; (p = *it); ++it)
{
buffer[i++] = sep;
l = strlen (p);
memcpy (buffer + i, p, l);
i += l;
}
}
buffer[i] = '\0';
}
char*
shtty_attr_to_string(ttp)
TTYSTRUCT *ttp;
{
char** vec;
int i;
size_t alloc_size;
char* ret;
vec = strvec_create (60);
#define A(M, F) \
if (ttp->M & F) { \
vec[i++] = #F; \
alloc_size += sizeof (#F); \
}
i = 0;
alloc_size = 0;
A(c_iflag, IGNBRK)
A(c_iflag, BRKINT)
A(c_iflag, IGNPAR)
A(c_iflag, PARMRK)
A(c_iflag, INPCK)
A(c_iflag, ISTRIP)
A(c_iflag, INLCR)
A(c_iflag, IGNCR)
A(c_iflag, ICRNL)
A(c_iflag, IUCLC)
A(c_iflag, IXON)
A(c_iflag, IXANY)
A(c_iflag, IXOFF)
A(c_iflag, IMAXBEL)
A(c_iflag, IUTF8)
A(c_oflag, OPOST)
A(c_oflag, OLCUC)
A(c_oflag, ONLCR)
A(c_oflag, OCRNL)
A(c_oflag, ONOCR)
A(c_oflag, ONLRET)
A(c_oflag, OFILL)
A(c_oflag, OFDEL)
A(c_oflag, NLDLY)
A(c_oflag, CRDLY)
A(c_oflag, TABDLY)
A(c_oflag, BSDLY)
A(c_oflag, VTDLY)
A(c_oflag, FFDLY)
A(c_cflag, CBAUD)
A(c_cflag, CBAUDEX)
A(c_cflag, CSIZE)
A(c_cflag, CSTOPB)
A(c_cflag, CREAD)
A(c_cflag, PARENB)
A(c_cflag, PARODD)
A(c_cflag, HUPCL)
A(c_cflag, CLOCAL)
// A(c_cflag, LOBLK)
A(c_cflag, CIBAUD)
A(c_cflag, CMSPAR)
A(c_cflag, CRTSCTS)
A(c_lflag, ICANON)
A(c_lflag, XCASE)
A(c_lflag, ECHO)
A(c_lflag, ECHOE)
A(c_lflag, ECHOK)
A(c_lflag, ECHONL)
A(c_lflag, ECHOCTL)
A(c_lflag, ECHOPRT)
A(c_lflag, ECHOKE)
// A(c_lflag, DEFECHO)
A(c_lflag, FLUSHO)
A(c_lflag, NOFLSH)
A(c_lflag, TOSTOP)
A(c_lflag, PENDIN)
A(c_lflag, IEXTEN)
if (i == 0)
ret = savestring("");
else if (i == 1)
ret = savestring(vec[0]);
else {
vec[i] = 0;
strvec_sort (vec);
ret = xmalloc (alloc_size);
shttyvariables_strvec_to_string (vec, ret, ' ');
}
free(vec);
#undef A
return ret;
}
void
shtty_print_attr(prefix, ttp)
char* prefix;
TTYSTRUCT *ttp;
{
char* str;
str = shtty_attr_to_string (ttp);
fprintf(stderr, "%s: %s\n", prefix, str);
free(str);
}
int
ttgetattr(fd, ttp)
int fd;
TTYSTRUCT *ttp;
{
fprintf(stderr, "ttgetattr(%d, %p)\n", fd, ttp);
int r;
#ifdef TERMIOS_TTY_DRIVER
r = tcgetattr(fd, ttp);
#else
# ifdef TERMIO_TTY_DRIVER
r = ioctl(fd, TCGETA, ttp);
# else
r = ioctl(fd, TIOCGETP, ttp);
# endif
#endif
shtty_print_attr("ttgetattr", ttp);
fprintf(stderr, "ttgetattr: ret: %d\n", r);
return r;
}
int
ttsetattr(fd, ttp)
int fd;
TTYSTRUCT *ttp;
{
fprintf(stderr, "ttsetattr(%d, %p)\n", fd, ttp);
shtty_print_attr("ttsetattr", ttp);
int r;
#ifdef TERMIOS_TTY_DRIVER
r = tcsetattr(fd, TCSADRAIN, ttp);
#else
# ifdef TERMIO_TTY_DRIVER
r = ioctl(fd, TCSETAW, ttp);
# else
r = ioctl(fd, TIOCSETN, ttp);
# endif
#endif
fprintf(stderr, "ttsetattr: ret: %d\n", r);
return r;
}
void
ttsave()
{
fprintf(stderr, "ttysave()\n");
if (ttsaved) {
fprintf(stderr, "ttysave: ttsaved\n");
} else {
ttgetattr (0, &ttin);
ttgetattr (1, &ttout);
ttsaved = 1;
}
fprintf(stderr, "ttysave: returns\n");
}
void
ttrestore()
{
fprintf(stderr, "ttrestore()\n");
if (ttsaved) {
fprintf(stderr, "ttrestore: ttsaved\n");
ttsetattr (0, &ttin);
ttsetattr (1, &ttout);
ttsaved = 0;
}
fprintf(stderr, "ttrestore: returns\n");
}
/* Retrieve the internally-saved attributes associated with tty fd FD. */
TTYSTRUCT *
ttattr (fd)
int fd;
{
fprintf(stderr, "ttattr(%d)\n", fd);
TTYSTRUCT* r;
if (ttsaved == 0)
r = ((TTYSTRUCT *)0);
else if (fd == 0)
r = &ttin;
else if (fd == 1)
r = &ttout;
else
r = ((TTYSTRUCT *)0);
fprintf(stderr, "ttattr: ret: %p\n", r);
return r;
}
/*
* Change attributes in ttp so that when it is installed using
* ttsetattr, the terminal will be in one-char-at-a-time mode.
*/
int
tt_setonechar(ttp)
TTYSTRUCT *ttp;
{
fprintf(stderr, "tt_setonechar(%p)\n", ttp);
#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER)
/* XXX - might not want this -- it disables erase and kill processing. */
ttp->c_lflag &= ~ICANON;
ttp->c_lflag |= ISIG;
# ifdef IEXTEN
ttp->c_lflag |= IEXTEN;
# endif
ttp->c_iflag |= ICRNL; /* make sure we get CR->NL on input */
ttp->c_iflag &= ~INLCR; /* but no NL->CR */
# ifdef OPOST
ttp->c_oflag |= OPOST;
# endif
# ifdef ONLCR
ttp->c_oflag |= ONLCR;
# endif
# ifdef OCRNL
ttp->c_oflag &= ~OCRNL;
# endif
# ifdef ONOCR
ttp->c_oflag &= ~ONOCR;
# endif
# ifdef ONLRET
ttp->c_oflag &= ~ONLRET;
# endif
ttp->c_cc[VMIN] = 1;
ttp->c_cc[VTIME] = 0;
#else
ttp->sg_flags |= CBREAK;
#endif
fprintf(stderr, "ttattr: tt_setonechar: ret: 0 (default)\n");
return 0;
}
/* Set the tty associated with FD and TTP into one-character-at-a-time mode */
int
ttfd_onechar (fd, ttp)
int fd;
TTYSTRUCT *ttp;
{
fprintf(stderr, "ttfd_onechar()\n");
int r;
r = tt_setonechar(ttp) < 0 ? -1 : ttsetattr (fd, ttp);
fprintf(stderr, "ttfd_onechar: ret: %d\n", r);
return r;
}
/* Set the terminal into one-character-at-a-time mode */
int
ttonechar ()
{
fprintf(stderr, "ttonechar()\n");
TTYSTRUCT tt;
int r;
if (ttsaved == 0)
r = -1;
else {
tt = ttin;
r = ttfd_onechar(0, &tt);
}
fprintf(stderr, "ttonechar: ret: %d\n", r);
return r;
}
/*
* Change attributes in ttp so that when it is installed using
* ttsetattr, the terminal will be in no-echo mode.
*/
int
tt_setnoecho(ttp)
TTYSTRUCT *ttp;
{
fprintf(stderr, "tt_setnoecho(%p)\n", ttp);
#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER)
ttp->c_lflag &= ~(ECHO|ECHOK|ECHONL);
#else
ttp->sg_flags &= ~ECHO;
#endif
fprintf(stderr, "tt_setnoecho: ret: 0 (default)\n");
return 0;
}
/* Set the tty associated with FD and TTP into no-echo mode */
int
ttfd_noecho (fd, ttp)
int fd;
TTYSTRUCT *ttp;
{
fprintf(stderr, "ttfd_noecho(%d, %p)\n", fd, ttp);
int r;
r = tt_setnoecho(ttp) < 0 ? -1 : ttsetattr(fd, ttp);
fprintf(stderr, "ttfd_noecho: ret: %d\n", r);
return r;
}
/* Set the terminal into no-echo mode */
int
ttnoecho ()
{
fprintf(stderr, "ttnoecho()\n");
TTYSTRUCT tt;
int r;
if (ttsaved == 0)
r = -1;
else {
tt = ttin;
r = (ttfd_noecho (0, &tt));
}
fprintf(stderr, "ttnoecho: ret: %d\n", r);
return r;
}
/*
* Change attributes in ttp so that when it is installed using
* ttsetattr, the terminal will be in eight-bit mode (pass8).
*/
int
tt_seteightbit (ttp)
TTYSTRUCT *ttp;
{
fprintf(stderr, "tt_seteightbit(%p)\n", ttp);
#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER)
ttp->c_iflag &= ~ISTRIP;
ttp->c_cflag |= CS8;
ttp->c_cflag &= ~PARENB;
#else
ttp->sg_flags |= ANYP;
#endif
fprintf(stderr, "tt_seteightbit: ret: 0 (default)\n");
return 0;
}
/* Set the tty associated with FD and TTP into eight-bit mode */
int
ttfd_eightbit (fd, ttp)
int fd;
TTYSTRUCT *ttp;
{
int r;
fprintf(stderr, "ttfd_eightbit(%d, %p)\n", fd, ttp);
r = tt_seteightbit (ttp) < 0 ? -1 : ttsetattr (fd, ttp);
fprintf(stderr, "ttfd_eightbit: ret: %d\n", r);
return r;
}
/* Set the terminal into eight-bit mode */
int
tteightbit ()
{
TTYSTRUCT tt;
fprintf(stderr, "tteightbit()\n");
int r;
if (ttsaved == 0)
r = -1;
else {
tt = ttin;
r = (ttfd_eightbit (0, &tt));
}
fprintf(stderr, "tteightbit: ret: %d\n", r);
return r;
}
/*
* Change attributes in ttp so that when it is installed using
* ttsetattr, the terminal will be in non-canonical input mode.
*/
int
tt_setnocanon (ttp)
TTYSTRUCT *ttp;
{
fprintf(stderr, "tt_setnocanon(%p)\n", ttp);
#if defined (TERMIOS_TTY_DRIVER) || defined (TERMIO_TTY_DRIVER)
ttp->c_lflag &= ~ICANON;
#endif
fprintf(stderr, "tt_setnocanon: ret: 0 (default)\n");
return 0;
}
/* Set the tty associated with FD and TTP into non-canonical mode */
int
ttfd_nocanon (fd, ttp)
int fd;
TTYSTRUCT *ttp;
{
int r;
fprintf(stderr, "ttfd_nocanon(%d, %p)\n", fd, ttp);
r = (tt_setnocanon (ttp) < 0) ? -1 : (ttsetattr (fd, ttp));
fprintf(stderr, "ttfd_nocanon: ret: %d\n", r);
return r;
}
/* Set the terminal into non-canonical mode */
int
ttnocanon ()
{
fprintf(stderr, "ttnocanon()\n");
TTYSTRUCT tt;
int r;
if (ttsaved == 0)
r = -1;
else {
tt = ttin;
r = (ttfd_nocanon (0, &tt));
}
fprintf(stderr, "ttnocanon: ret: %d\n", r);
return r;
}
/*
* Change attributes in ttp so that when it is installed using
* ttsetattr, the terminal will be in cbreak, no-echo mode.
*/
int
tt_setcbreak(ttp)
TTYSTRUCT *ttp;
{
fprintf(stderr, "tt_setcbreak(%p)\n", ttp);
int r;
r = (tt_setonechar (ttp) < 0) ? -1 : (tt_setnoecho (ttp));
fprintf(stderr, "tt_setcbreak: ret: %d\n", r);
return r;
}
/* Set the tty associated with FD and TTP into cbreak (no-echo,
one-character-at-a-time) mode */
int
ttfd_cbreak (fd, ttp)
int fd;
TTYSTRUCT *ttp;
{
fprintf(stderr, "ttfd_cbreak(%d, %p)\n", fd, ttp);
int r;
r = (tt_setcbreak (ttp) < 0) ? -1 : (ttsetattr (fd, ttp));
fprintf(stderr, "ttfd_cbreak: ret: %d\n", r);
return r;
}
/* Set the terminal into cbreak (no-echo, one-character-at-a-time) mode */
int
ttcbreak ()
{
TTYSTRUCT tt;
fprintf(stderr, "ttcbreak()\n");
int r;
if (ttsaved == 0)
r = -1;
else {
tt = ttin;
r = (ttfd_cbreak (0, &tt));
}
fprintf(stderr, "ttcbreak: ret: %d\n", r);
}