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