[BACK]Return to tty.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mail

Diff for /src/usr.bin/mail/tty.c between version 1.20 and 1.21

version 1.20, 2014/01/17 18:42:30 version 1.21, 2017/06/28 14:58:23
Line 40 
Line 40 
 #include "extern.h"  #include "extern.h"
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
 #include <errno.h>  #include <errno.h>
   #include <fcntl.h>
   
 static  cc_t            c_erase;        /* Current erase char */  #define TABWIDTH        8
 static  cc_t            c_kill;         /* Current kill char */  
 #ifndef TIOCSTI  struct tty {
 static  int             ttyset;         /* We must now do erase/kill */          int      fdin;
 #endif          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? */  static  volatile sig_atomic_t   ttysignal;      /* Interrupted by a signal? */
   
 /*  /*
Line 54 
Line 73 
 int  int
 grabh(struct header *hp, int gflags)  grabh(struct header *hp, int gflags)
 {  {
         struct termios ttybuf;          struct termios newtio, oldtio;
 #ifndef TIOCSTI  #ifdef TIOCEXT
         struct sigaction savequit;  
 #else  
 # ifdef TIOCEXT  
         int extproc;          int extproc;
         int flag;          int flag;
 # endif /* TIOCEXT */  
 #endif  #endif
         struct sigaction savetstp;          struct sigaction savetstp;
         struct sigaction savettou;          struct sigaction savettou;
Line 77 
Line 92 
         (void)sigaction(SIGTTOU, &act, &savettou);          (void)sigaction(SIGTTOU, &act, &savettou);
         (void)sigaction(SIGTTIN, &act, &savettin);          (void)sigaction(SIGTTIN, &act, &savettin);
         error = 1;          error = 1;
 #ifndef TIOCSTI          memset(&tty, 0, sizeof(tty));
         ttyset = 0;          tty.fdin = fileno(stdin);
 #endif          tty.fdout = fileno(stdout);
         if (tcgetattr(fileno(stdin), &ttybuf) < 0) {          if (tcgetattr(tty.fdin, &oldtio) < 0) {
                 warn("tcgetattr");                  warn("tcgetattr");
                 return(-1);                  return(-1);
         }          }
         c_erase = ttybuf.c_cc[VERASE];          tty.keys = oldtio.c_cc;
         c_kill = ttybuf.c_cc[VKILL];          if (oldtio.c_lflag & ALTWERASE)
 #ifndef TIOCSTI                  tty.flags |= TTY_ALTWERASE;
         ttybuf.c_cc[VERASE] = 0;  
         ttybuf.c_cc[VKILL] = 0;          newtio = oldtio;
         act.sa_handler = SIG_IGN;          newtio.c_lflag &= ~(ECHO | ICANON);
         if (sigaction(SIGQUIT, &act, &savequit) == 0 &&          newtio.c_cc[VMIN] = 1;
             savequit.sa_handler == SIG_DFL)          newtio.c_cc[VTIME] = 0;
                 (void)sigaction(SIGQUIT, &savequit, NULL);          if (tcsetattr(tty.fdin, TCSADRAIN, &newtio) < 0) {
 #else                  warn("tcsetattr");
 # ifdef TIOCEXT                  return(-1);
         extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);          }
   
   #ifdef TIOCEXT
           extproc = ((oldtio.c_lflag & EXTPROC) ? 1 : 0);
         if (extproc) {          if (extproc) {
                 flag = 0;                  flag = 0;
                 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)                  if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                         warn("TIOCEXT: off");                          warn("TIOCEXT: off");
         }          }
 # endif /* TIOCEXT */  
 #endif  #endif
         if (gflags & GTO) {          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));                  s = readtty("To: ", detract(hp->h_to, 0));
                 if (s == NULL)                  if (s == NULL)
                         goto out;                          goto out;
                 hp->h_to = extract(s, GTO);                  hp->h_to = extract(s, GTO);
         }          }
         if (gflags & GSUBJECT) {          if (gflags & GSUBJECT) {
 #ifndef TIOCSTI  
                 if (!ttyset && hp->h_subject != NULL)  
                         ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);  
 #endif  
                 s = readtty("Subject: ", hp->h_subject);                  s = readtty("Subject: ", hp->h_subject);
                 if (s == NULL)                  if (s == NULL)
                         goto out;                          goto out;
                 hp->h_subject = s;                  hp->h_subject = s;
         }          }
         if (gflags & GCC) {          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));                  s = readtty("Cc: ", detract(hp->h_cc, 0));
                 if (s == NULL)                  if (s == NULL)
                         goto out;                          goto out;
                 hp->h_cc = extract(s, GCC);                  hp->h_cc = extract(s, GCC);
         }          }
         if (gflags & GBCC) {          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));                  s = readtty("Bcc: ", detract(hp->h_bcc, 0));
                 if (s == NULL)                  if (s == NULL)
                         goto out;                          goto out;
Line 148 
Line 149 
         (void)sigaction(SIGTSTP, &savetstp, NULL);          (void)sigaction(SIGTSTP, &savetstp, NULL);
         (void)sigaction(SIGTTOU, &savettou, NULL);          (void)sigaction(SIGTTOU, &savettou, NULL);
         (void)sigaction(SIGTTIN, &savettin, NULL);          (void)sigaction(SIGTTIN, &savettin, NULL);
 #ifndef TIOCSTI  #ifdef TIOCEXT
         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) {          if (extproc) {
                 flag = 1;                  flag = 1;
                 if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)                  if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
                         warn("TIOCEXT: on");                          warn("TIOCEXT: on");
         }          }
 # endif /* TIOCEXT */  
 #endif  #endif
           if (tcsetattr(tty.fdin, TCSADRAIN, &oldtio) < 0)
                   warn("tcsetattr");
         return(error);          return(error);
 }  }
   
Line 176 
Line 171 
 readtty(char *pr, char *src)  readtty(char *pr, char *src)
 {  {
         struct sigaction act, saveint;          struct sigaction act, saveint;
         char ch, canonb[BUFSIZ];          unsigned char canonb[BUFSIZ];
         char *cp, *cp2;          char *cp;
         sigset_t oset;          sigset_t oset;
         int c;          int c, done;
   
         fputs(pr, stdout);          memset(canonb, 0, sizeof(canonb));
         fflush(stdout);          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) {          if (src != NULL && strlen(src) > sizeof(canonb) - 2) {
                 puts("too long to edit");                  puts("too long to edit");
                 return(src);                  return(src);
         }          }
 #ifndef TIOCSTI          if (src != NULL) {
         if (src != NULL)                  for (cp = src; *cp != '\0'; cp++)
                 cp = copy(src, canonb); /* safe, bounds checked above */                          tty_insert(&tty, *cp, 1);
         else                  tty_flush(&tty);
                 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);          sigemptyset(&act.sa_mask);
         act.sa_flags = 0;               /* Note: will not restart syscalls */          act.sa_flags = 0;               /* Note: will not restart syscalls */
         act.sa_handler = ttyint;          act.sa_handler = ttyint;
Line 217 
Line 204 
         (void)sigaction(SIGTTOU, &act, NULL);          (void)sigaction(SIGTTOU, &act, NULL);
         (void)sigaction(SIGTTIN, &act, NULL);          (void)sigaction(SIGTTIN, &act, NULL);
         (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);          (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
         clearerr(stdin);          for (;;) {
         memset(cp, 0, canonb + sizeof(canonb) - cp);                  c = tty_getc(&tty);
         for (cp2 = cp; cp2 < canonb + sizeof(canonb) - 1; ) {  
                 c = getc(stdin);  
                 switch (ttysignal) {                  switch (ttysignal) {
                         case SIGINT:                          case SIGINT:
                                 ttysignal = 0;                                  tty_visc(&tty, '\003'); /* output ^C */
                                 cp2 = NULL;  
                                 c = EOF;  
                                 /* FALLTHROUGH */                                  /* FALLTHROUGH */
                         case 0:                          case 0:
                                 break;                                  break;
Line 233 
Line 216 
                                 ttysignal = 0;                                  ttysignal = 0;
                                 goto redo;                                  goto redo;
                 }                  }
                 if (c == EOF || c == '\n')                  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;                          break;
                 *cp2++ = c;  
         }          }
         act.sa_handler = SIG_DFL;          act.sa_handler = SIG_DFL;
         sigemptyset(&act.sa_mask);          sigemptyset(&act.sa_mask);
Line 245 
Line 236 
         (void)sigaction(SIGTTOU, &act, NULL);          (void)sigaction(SIGTTOU, &act, NULL);
         (void)sigaction(SIGTTIN, &act, NULL);          (void)sigaction(SIGTTIN, &act, NULL);
         (void)sigaction(SIGINT, &saveint, NULL);          (void)sigaction(SIGINT, &saveint, NULL);
         if (cp2 == NULL)          if (tty.flags & TTY_ERR) {
                 return(NULL);                   /* user hit ^C */                  if (ttysignal == SIGINT) {
         *cp2 = '\0';                          ttysignal = 0;
         if (c == EOF && ferror(stdin)) {                          return(NULL);   /* user hit ^C */
                   }
   
 redo:  redo:
                 cp = strlen(canonb) > 0 ? canonb : NULL;                  cp = strlen(canonb) > 0 ? canonb : NULL;
                 clearerr(stdin);  
                 /* XXX - make iterative, not recursive */                  /* XXX - make iterative, not recursive */
                 return(readtty(pr, cp));                  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))          if (equal("", canonb))
                 return("");                  return("");
         return(savestr(canonb));          return(savestr(canonb));
Line 327 
Line 287 
 {  {
   
         ttysignal = s;          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);
           }
 }  }

Legend:
Removed from v.1.20  
changed lines
  Added in v.1.21