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

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