/* * 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); }