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

Annotation of src/usr.bin/mg/ttyio.c, Revision 1.35

1.35    ! lum         1: /*     $OpenBSD: ttyio.c,v 1.34 2013/04/20 17:39:50 deraadt Exp $      */
1.28      kjell       2:
                      3: /* This file is in the public domain. */
1.13      niklas      4:
1.1       deraadt     5: /*
1.5       millert     6:  * POSIX terminal I/O.
1.1       deraadt     7:  *
1.23      vincent     8:  * The functions in this file negotiate with the operating system for
                      9:  * keyboard characters, and write characters to the display in a barely
                     10:  * buffered fashion.
1.1       deraadt    11:  */
1.26      db         12: #include "def.h"
1.1       deraadt    13:
1.26      db         14: #include <sys/types.h>
                     15: #include <sys/time.h>
                     16: #include <sys/ioctl.h>
                     17: #include <fcntl.h>
1.34      deraadt    18: #include <poll.h>
1.26      db         19: #include <termios.h>
                     20: #include <term.h>
1.1       deraadt    21:
1.23      vincent    22: #define NOBUF  512                     /* Output buffer size. */
1.1       deraadt    23:
1.7       millert    24: #ifndef TCSASOFT
                     25: #define TCSASOFT       0
                     26: #endif
                     27:
1.24      vincent    28: int    ttstarted;
1.23      vincent    29: char   obuf[NOBUF];                    /* Output buffer. */
1.31      deraadt    30: size_t nobuf;                          /* Buffer count. */
1.23      vincent    31: struct termios oldtty;                 /* POSIX tty settings. */
1.8       millert    32: struct termios newtty;
1.23      vincent    33: int    nrow;                           /* Terminal size, rows. */
                     34: int    ncol;                           /* Terminal size, columns. */
1.1       deraadt    35:
1.8       millert    36: /*
1.10      millert    37:  * This function gets called once, to set up the terminal.
1.8       millert    38:  * On systems w/o TCSASOFT we turn off off flow control,
                     39:  * which isn't really the right thing to do.
1.1       deraadt    40:  */
1.8       millert    41: void
1.23      vincent    42: ttopen(void)
1.1       deraadt    43: {
1.12      millert    44:        if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))
1.16      mickey     45:                panic("standard input and output must be a terminal");
1.12      millert    46:
1.8       millert    47:        if (ttraw() == FALSE)
                     48:                panic("aborting due to terminal initialize failure");
                     49: }
1.1       deraadt    50:
1.8       millert    51: /*
                     52:  * This function sets the terminal to RAW mode, as defined for the current
                     53:  * shell.  This is called both by ttopen() above and by spawncli() to
                     54:  * get the current terminal settings and then change them to what
                     55:  * mg expects. Thus, tty changes done while spawncli() is in effect
                     56:  * will be reflected in mg.
                     57:  */
                     58: int
1.23      vincent    59: ttraw(void)
1.8       millert    60: {
                     61:        if (tcgetattr(0, &oldtty) < 0) {
1.35    ! lum        62:                dobeep();
1.8       millert    63:                ewprintf("ttopen can't get terminal attributes");
1.23      vincent    64:                return (FALSE);
1.8       millert    65:        }
                     66:        (void)memcpy(&newtty, &oldtty, sizeof(newtty));
                     67:        /* Set terminal to 'raw' mode and ignore a 'break' */
                     68:        newtty.c_cc[VMIN] = 1;
                     69:        newtty.c_cc[VTIME] = 0;
                     70:        newtty.c_iflag |= IGNBRK;
                     71:        newtty.c_iflag &= ~(BRKINT | PARMRK | INLCR | IGNCR | ICRNL | IXON);
                     72:        newtty.c_oflag &= ~OPOST;
                     73:        newtty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
1.7       millert    74:
                     75: #if !TCSASOFT
1.8       millert    76:        /*
                     77:         * If we don't have TCSASOFT, force terminal to
                     78:         * 8 bits, no parity.
                     79:         */
                     80:        newtty.c_iflag &= ~ISTRIP;
                     81:        newtty.c_cflag &= ~(CSIZE | PARENB);
                     82:        newtty.c_cflag |= CS8;
1.7       millert    83: #endif
1.8       millert    84:        if (tcsetattr(0, TCSASOFT | TCSADRAIN, &newtty) < 0) {
1.35    ! lum        85:                dobeep();
1.8       millert    86:                ewprintf("ttopen can't tcsetattr");
1.23      vincent    87:                return (FALSE);
1.8       millert    88:        }
1.24      vincent    89:        ttstarted = 1;
                     90:
1.23      vincent    91:        return (TRUE);
1.8       millert    92: }
1.1       deraadt    93:
1.8       millert    94: /*
                     95:  * This function gets called just before we go back home to the shell.
                     96:  * Put all of the terminal parameters back.
                     97:  * Under UN*X this just calls ttcooked(), but the ttclose() hook is in
                     98:  * because vttidy() in display.c expects it for portability reasons.
                     99:  */
                    100: void
1.23      vincent   101: ttclose(void)
1.8       millert   102: {
1.24      vincent   103:        if (ttstarted) {
                    104:                if (ttcooked() == FALSE)
                    105:                        panic("");      /* ttcooked() already printf'd */
                    106:                ttstarted = 0;
                    107:        }
1.1       deraadt   108: }
                    109:
                    110: /*
1.8       millert   111:  * This function restores all terminal settings to their default values,
                    112:  * in anticipation of exiting or suspending the editor.
1.1       deraadt   113:  */
1.8       millert   114: int
1.23      vincent   115: ttcooked(void)
1.1       deraadt   116: {
                    117:        ttflush();
1.8       millert   118:        if (tcsetattr(0, TCSASOFT | TCSADRAIN, &oldtty) < 0) {
1.35    ! lum       119:                dobeep();
1.8       millert   120:                ewprintf("ttclose can't tcsetattr");
1.23      vincent   121:                return (FALSE);
1.8       millert   122:        }
1.23      vincent   123:        return (TRUE);
1.1       deraadt   124: }
                    125:
                    126: /*
1.8       millert   127:  * Write character to the display.  Characters are buffered up,
                    128:  * to make things a little bit more efficient.
1.1       deraadt   129:  */
1.11      millert   130: int
1.19      millert   131: ttputc(int c)
1.1       deraadt   132: {
                    133:        if (nobuf >= NOBUF)
                    134:                ttflush();
                    135:        obuf[nobuf++] = c;
1.23      vincent   136:        return (c);
1.1       deraadt   137: }
                    138:
                    139: /*
                    140:  * Flush output.
                    141:  */
1.8       millert   142: void
1.23      vincent   143: ttflush(void)
1.1       deraadt   144: {
1.26      db        145:        ssize_t  written;
                    146:        char    *buf = obuf;
1.22      deraadt   147:
1.19      millert   148:        if (nobuf == 0)
                    149:                return;
1.5       millert   150:
1.20      millert   151:        while ((written = write(fileno(stdout), buf, nobuf)) != nobuf) {
1.32      reyk      152:                if (written == -1) {
                    153:                        if (errno == EINTR)
                    154:                                continue;
1.8       millert   155:                        panic("ttflush write failed");
1.32      reyk      156:                }
1.20      millert   157:                buf += written;
                    158:                nobuf -= written;
1.1       deraadt   159:        }
1.21      millert   160:        nobuf = 0;
1.1       deraadt   161: }
                    162:
                    163: /*
1.23      vincent   164:  * Read character from terminal. All 8 bits are returned, so that you
                    165:  * can use a multi-national terminal.
1.1       deraadt   166:  */
1.8       millert   167: int
1.23      vincent   168: ttgetc(void)
1.1       deraadt   169: {
1.9       millert   170:        char    c;
1.30      deraadt   171:        ssize_t ret;
1.5       millert   172:
1.18      deraadt   173:        do {
1.27      deraadt   174:                ret = read(STDIN_FILENO, &c, 1);
1.18      deraadt   175:                if (ret == -1 && errno == EINTR) {
                    176:                        if (winch_flag) {
1.29      kjell     177:                                redraw(0, 0);
1.18      deraadt   178:                                winch_flag = 0;
                    179:                        }
1.33      florian   180:                } else if (ret == -1 && errno == EIO)
                    181:                        panic("lost stdin");
                    182:                else if (ret == 1)
1.18      deraadt   183:                        break;
                    184:        } while (1);
1.25      vincent   185:        return ((int) c) & 0xFF;
1.1       deraadt   186: }
                    187:
1.8       millert   188: /*
                    189:  * Returns TRUE if there are characters waiting to be read.
                    190:  */
                    191: int
1.29      kjell     192: charswaiting(void)
1.8       millert   193: {
                    194:        int     x;
                    195:
1.30      deraadt   196:        return ((ioctl(0, FIONREAD, &x) < 0) ? 0 : x);
1.8       millert   197: }
                    198:
                    199: /*
                    200:  * panic - just exit, as quickly as we can.
                    201:  */
1.15      art       202: void
1.19      millert   203: panic(char *s)
1.8       millert   204: {
1.33      florian   205:        static int panicking = 0;
                    206:
                    207:        if (panicking)
                    208:                return;
                    209:        else
                    210:                panicking = 1;
1.24      vincent   211:        ttclose();
1.8       millert   212:        (void) fputs("panic: ", stderr);
                    213:        (void) fputs(s, stderr);
                    214:        (void) fputc('\n', stderr);
1.12      millert   215:        exit(1);
1.8       millert   216: }
                    217:
1.1       deraadt   218: /*
1.14      art       219:  * This function returns FALSE if any characters have showed up on the
1.26      db        220:  * tty before 'msec' milliseconds.
1.1       deraadt   221:  */
1.8       millert   222: int
1.14      art       223: ttwait(int msec)
1.1       deraadt   224: {
1.34      deraadt   225:        struct pollfd   pfd[1];
1.5       millert   226:
1.34      deraadt   227:        pfd[0].fd = 0;
                    228:        pfd[0].events = POLLIN;
1.5       millert   229:
1.34      deraadt   230:        if ((poll(pfd, 1, msec)) == 0)
1.8       millert   231:                return (TRUE);
                    232:        return (FALSE);
1.1       deraadt   233: }