[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.26

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