=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/mail/tty.c,v retrieving revision 1.20 retrieving revision 1.21 diff -c -r1.20 -r1.21 *** src/usr.bin/mail/tty.c 2014/01/17 18:42:30 1.20 --- src/usr.bin/mail/tty.c 2017/06/28 14:58:23 1.21 *************** *** 1,4 **** ! /* $OpenBSD: tty.c,v 1.20 2014/01/17 18:42:30 okan Exp $ */ /* $NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $ */ /* --- 1,4 ---- ! /* $OpenBSD: tty.c,v 1.21 2017/06/28 14:58:23 anton Exp $ */ /* $NetBSD: tty.c,v 1.7 1997/07/09 05:25:46 mikel Exp $ */ /* *************** *** 40,51 **** #include "extern.h" #include #include ! static cc_t c_erase; /* Current erase char */ ! static cc_t c_kill; /* Current kill char */ ! #ifndef TIOCSTI ! static int ttyset; /* We must now do erase/kill */ ! #endif static volatile sig_atomic_t ttysignal; /* Interrupted by a signal? */ /* --- 40,70 ---- #include "extern.h" #include #include + #include ! #define TABWIDTH 8 ! ! struct tty { ! int fdin; ! int fdout; ! int flags; ! #define TTY_ALTWERASE 0x1 ! #define TTY_ERR 0x2 ! cc_t *keys; ! char *buf; ! size_t size; ! size_t len; ! size_t cursor; ! }; ! ! static void tty_flush(struct tty *); ! static int tty_getc(struct tty *); ! static int tty_insert(struct tty *, int, int); ! static void tty_putc(struct tty *, int); ! static void tty_reset(struct tty *); ! static void tty_visc(struct tty *, int); ! ! static struct tty tty; static volatile sig_atomic_t ttysignal; /* Interrupted by a signal? */ /* *************** *** 54,67 **** int grabh(struct header *hp, int gflags) { ! struct termios ttybuf; ! #ifndef TIOCSTI ! struct sigaction savequit; ! #else ! # ifdef TIOCEXT int extproc; int flag; - # endif /* TIOCEXT */ #endif struct sigaction savetstp; struct sigaction savettou; --- 73,82 ---- int grabh(struct header *hp, int gflags) { ! struct termios newtio, oldtio; ! #ifdef TIOCEXT int extproc; int flag; #endif struct sigaction savetstp; struct sigaction savettou; *************** *** 77,143 **** (void)sigaction(SIGTTOU, &act, &savettou); (void)sigaction(SIGTTIN, &act, &savettin); error = 1; ! #ifndef TIOCSTI ! ttyset = 0; ! #endif ! if (tcgetattr(fileno(stdin), &ttybuf) < 0) { warn("tcgetattr"); return(-1); } ! c_erase = ttybuf.c_cc[VERASE]; ! c_kill = ttybuf.c_cc[VKILL]; ! #ifndef TIOCSTI ! ttybuf.c_cc[VERASE] = 0; ! ttybuf.c_cc[VKILL] = 0; ! act.sa_handler = SIG_IGN; ! if (sigaction(SIGQUIT, &act, &savequit) == 0 && ! savequit.sa_handler == SIG_DFL) ! (void)sigaction(SIGQUIT, &savequit, NULL); ! #else ! # ifdef TIOCEXT ! extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0); if (extproc) { flag = 0; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: off"); } - # endif /* TIOCEXT */ #endif if (gflags & GTO) { - #ifndef TIOCSTI - if (!ttyset && hp->h_to != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); - #endif s = readtty("To: ", detract(hp->h_to, 0)); if (s == NULL) goto out; hp->h_to = extract(s, GTO); } if (gflags & GSUBJECT) { - #ifndef TIOCSTI - if (!ttyset && hp->h_subject != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); - #endif s = readtty("Subject: ", hp->h_subject); if (s == NULL) goto out; hp->h_subject = s; } if (gflags & GCC) { - #ifndef TIOCSTI - if (!ttyset && hp->h_cc != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); - #endif s = readtty("Cc: ", detract(hp->h_cc, 0)); if (s == NULL) goto out; hp->h_cc = extract(s, GCC); } if (gflags & GBCC) { - #ifndef TIOCSTI - if (!ttyset && hp->h_bcc != NULL) - ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); - #endif s = readtty("Bcc: ", detract(hp->h_bcc, 0)); if (s == NULL) goto out; --- 92,144 ---- (void)sigaction(SIGTTOU, &act, &savettou); (void)sigaction(SIGTTIN, &act, &savettin); error = 1; ! memset(&tty, 0, sizeof(tty)); ! tty.fdin = fileno(stdin); ! tty.fdout = fileno(stdout); ! if (tcgetattr(tty.fdin, &oldtio) < 0) { warn("tcgetattr"); return(-1); } ! tty.keys = oldtio.c_cc; ! if (oldtio.c_lflag & ALTWERASE) ! tty.flags |= TTY_ALTWERASE; ! ! newtio = oldtio; ! newtio.c_lflag &= ~(ECHO | ICANON); ! newtio.c_cc[VMIN] = 1; ! newtio.c_cc[VTIME] = 0; ! if (tcsetattr(tty.fdin, TCSADRAIN, &newtio) < 0) { ! warn("tcsetattr"); ! return(-1); ! } ! ! #ifdef TIOCEXT ! extproc = ((oldtio.c_lflag & EXTPROC) ? 1 : 0); if (extproc) { flag = 0; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: off"); } #endif if (gflags & GTO) { s = readtty("To: ", detract(hp->h_to, 0)); if (s == NULL) goto out; hp->h_to = extract(s, GTO); } if (gflags & GSUBJECT) { s = readtty("Subject: ", hp->h_subject); if (s == NULL) goto out; hp->h_subject = s; } if (gflags & GCC) { s = readtty("Cc: ", detract(hp->h_cc, 0)); if (s == NULL) goto out; hp->h_cc = extract(s, GCC); } if (gflags & GBCC) { s = readtty("Bcc: ", detract(hp->h_bcc, 0)); if (s == NULL) goto out; *************** *** 148,168 **** (void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTTOU, &savettou, NULL); (void)sigaction(SIGTTIN, &savettin, NULL); ! #ifndef TIOCSTI ! ttybuf.c_cc[VERASE] = c_erase; ! ttybuf.c_cc[VKILL] = c_kill; ! if (ttyset) ! tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf); ! (void)sigaction(SIGQUIT, &savequit, NULL); ! #else ! # ifdef TIOCEXT if (extproc) { flag = 1; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: on"); } - # endif /* TIOCEXT */ #endif return(error); } --- 149,163 ---- (void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTTOU, &savettou, NULL); (void)sigaction(SIGTTIN, &savettin, NULL); ! #ifdef TIOCEXT if (extproc) { flag = 1; if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0) warn("TIOCEXT: on"); } #endif + if (tcsetattr(tty.fdin, TCSADRAIN, &oldtio) < 0) + warn("tcsetattr"); return(error); } *************** *** 176,213 **** readtty(char *pr, char *src) { struct sigaction act, saveint; ! char ch, canonb[BUFSIZ]; ! char *cp, *cp2; sigset_t oset; ! int c; ! fputs(pr, stdout); ! fflush(stdout); if (src != NULL && strlen(src) > sizeof(canonb) - 2) { puts("too long to edit"); return(src); } ! #ifndef TIOCSTI ! if (src != NULL) ! cp = copy(src, canonb); /* safe, bounds checked above */ ! else ! cp = copy("", canonb); ! fputs(canonb, stdout); ! fflush(stdout); ! #else ! cp = src == NULL ? "" : src; ! while ((c = (unsigned char)*cp++) != '\0') { ! if ((c_erase != _POSIX_VDISABLE && c == c_erase) || ! (c_kill != _POSIX_VDISABLE && c == c_kill)) { ! ch = '\\'; ! ioctl(0, TIOCSTI, &ch); ! } ! ch = c; ! ioctl(0, TIOCSTI, &ch); } ! cp = canonb; ! *cp = 0; ! #endif sigemptyset(&act.sa_mask); act.sa_flags = 0; /* Note: will not restart syscalls */ act.sa_handler = ttyint; --- 171,200 ---- readtty(char *pr, char *src) { struct sigaction act, saveint; ! unsigned char canonb[BUFSIZ]; ! char *cp; sigset_t oset; ! int c, done; ! memset(canonb, 0, sizeof(canonb)); ! tty.buf = canonb; ! tty.size = sizeof(canonb) - 1; ! ! for (cp = pr; *cp != '\0'; cp++) ! tty_insert(&tty, *cp, 1); ! tty_flush(&tty); ! tty_reset(&tty); ! if (src != NULL && strlen(src) > sizeof(canonb) - 2) { puts("too long to edit"); return(src); } ! if (src != NULL) { ! for (cp = src; *cp != '\0'; cp++) ! tty_insert(&tty, *cp, 1); ! tty_flush(&tty); } ! sigemptyset(&act.sa_mask); act.sa_flags = 0; /* Note: will not restart syscalls */ act.sa_handler = ttyint; *************** *** 217,231 **** (void)sigaction(SIGTTOU, &act, NULL); (void)sigaction(SIGTTIN, &act, NULL); (void)sigprocmask(SIG_UNBLOCK, &intset, &oset); ! clearerr(stdin); ! memset(cp, 0, canonb + sizeof(canonb) - cp); ! for (cp2 = cp; cp2 < canonb + sizeof(canonb) - 1; ) { ! c = getc(stdin); switch (ttysignal) { case SIGINT: ! ttysignal = 0; ! cp2 = NULL; ! c = EOF; /* FALLTHROUGH */ case 0: break; --- 204,214 ---- (void)sigaction(SIGTTOU, &act, NULL); (void)sigaction(SIGTTIN, &act, NULL); (void)sigprocmask(SIG_UNBLOCK, &intset, &oset); ! for (;;) { ! c = tty_getc(&tty); switch (ttysignal) { case SIGINT: ! tty_visc(&tty, '\003'); /* output ^C */ /* FALLTHROUGH */ case 0: break; *************** *** 233,241 **** ttysignal = 0; goto redo; } ! if (c == EOF || c == '\n') break; - *cp2++ = c; } act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); --- 216,232 ---- ttysignal = 0; goto redo; } ! if (c == 0) { ! done = 1; ! } else if (c == '\n') { ! tty_putc(&tty, c); ! done = 1; ! } else { ! done = tty_insert(&tty, c, 0); ! tty_flush(&tty); ! } ! if (done) break; } act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); *************** *** 245,292 **** (void)sigaction(SIGTTOU, &act, NULL); (void)sigaction(SIGTTIN, &act, NULL); (void)sigaction(SIGINT, &saveint, NULL); ! if (cp2 == NULL) ! return(NULL); /* user hit ^C */ ! *cp2 = '\0'; ! if (c == EOF && ferror(stdin)) { redo: cp = strlen(canonb) > 0 ? canonb : NULL; - clearerr(stdin); /* XXX - make iterative, not recursive */ return(readtty(pr, cp)); } - #ifndef TIOCSTI - if (cp == NULL || *cp == '\0') - return(src); - cp2 = cp; - if (!ttyset) - return(strlen(canonb) > 0 ? savestr(canonb) : NULL); - while (*cp != '\0') { - c = (unsigned char)*cp++; - if (c_erase != _POSIX_VDISABLE && c == c_erase) { - if (cp2 == canonb) - continue; - if (cp2[-1] == '\\') { - cp2[-1] = c; - continue; - } - cp2--; - continue; - } - if (c_kill != _POSIX_VDISABLE && c == c_kill) { - if (cp2 == canonb) - continue; - if (cp2[-1] == '\\') { - cp2[-1] = c; - continue; - } - cp2 = canonb; - continue; - } - *cp2++ = c; - } - *cp2 = '\0'; - #endif if (equal("", canonb)) return(""); return(savestr(canonb)); --- 236,252 ---- (void)sigaction(SIGTTOU, &act, NULL); (void)sigaction(SIGTTIN, &act, NULL); (void)sigaction(SIGINT, &saveint, NULL); ! if (tty.flags & TTY_ERR) { ! if (ttysignal == SIGINT) { ! ttysignal = 0; ! return(NULL); /* user hit ^C */ ! } ! redo: cp = strlen(canonb) > 0 ? canonb : NULL; /* XXX - make iterative, not recursive */ return(readtty(pr, cp)); } if (equal("", canonb)) return(""); return(savestr(canonb)); *************** *** 327,330 **** --- 287,408 ---- { ttysignal = s; + } + + static void + tty_flush(struct tty *t) + { + size_t i, len; + int c; + + if (t->cursor < t->len) { + for (; t->cursor < t->len; t->cursor++) + tty_visc(t, t->buf[t->cursor]); + } else if (t->cursor > t->len) { + len = t->cursor - t->len; + for (i = len; i > 0; i--) { + c = t->buf[--t->cursor]; + if (c == '\t') + len += TABWIDTH - 1; + else if (iscntrl(c)) + len++; /* account for leading ^ */ + } + for (i = 0; i < len; i++) + tty_putc(t, '\b'); + for (i = 0; i < len; i++) + tty_putc(t, ' '); + for (i = 0; i < len; i++) + tty_putc(t, '\b'); + t->cursor = t->len; + } + + t->buf[t->len] = '\0'; + } + + static int + tty_getc(struct tty *t) + { + ssize_t n; + unsigned char c; + + n = read(t->fdin, &c, 1); + switch (n) { + case -1: + t->flags |= TTY_ERR; + /* FALLTHROUGH */ + case 0: + return 0; + default: + return c & 0x7f; + } + } + + static int + tty_insert(struct tty *t, int c, int nocntrl) + { + const unsigned char *ws = " \t"; + + if (CCEQ(t->keys[VERASE], c)) { + if (nocntrl) + return 0; + if (t->len > 0) + t->len--; + } else if (CCEQ(t->keys[VWERASE], c)) { + if (nocntrl) + return 0; + for (; t->len > 0; t->len--) + if (strchr(ws, t->buf[t->len - 1]) == NULL + && ((t->flags & TTY_ALTWERASE) == 0 + || isalpha(t->buf[t->len - 1]))) + break; + for (; t->len > 0; t->len--) + if (strchr(ws, t->buf[t->len - 1]) != NULL + || ((t->flags & TTY_ALTWERASE) + && !isalpha(t->buf[t->len - 1]))) + break; + } else if (CCEQ(t->keys[VKILL], c)) { + if (nocntrl) + return 0; + t->len = 0; + } else { + if (t->len == t->size) + return 1; + t->buf[t->len++] = c; + } + + return 0; + } + + static void + tty_putc(struct tty *t, int c) + { + unsigned char cc = c; + + write(t->fdout, &cc, 1); + } + + static void + tty_reset(struct tty *t) + { + memset(t->buf, 0, t->len); + t->len = t->cursor = 0; + } + + static void + tty_visc(struct tty *t, int c) + { + int i; + + if (c == '\t') { + for (i = 0; i < TABWIDTH; i++) + tty_putc(t, ' '); + } else if (iscntrl(c)) { + tty_putc(t, '^'); + if (c == 0x7F) + tty_putc(t, '?'); + else + tty_putc(t, (c | 0x40)); + } else { + tty_putc(t, c); + } }