Annotation of src/usr.bin/mg/ttyio.c, Revision 1.12
1.1 deraadt 1: /*
1.5 millert 2: * POSIX terminal I/O.
1.1 deraadt 3: *
4: * The functions in this file
5: * negotiate with the operating system for
6: * keyboard characters, and write characters to
7: * the display in a barely buffered fashion.
8: */
9: #include "def.h"
10:
11: #include <sys/types.h>
1.5 millert 12: #include <sys/time.h>
13: #include <sys/ioctl.h>
1.1 deraadt 14: #include <fcntl.h>
1.2 deraadt 15: #include <termios.h>
1.4 millert 16: #include <term.h>
1.1 deraadt 17:
1.8 millert 18: #define NOBUF 512 /* Output buffer size. */
1.1 deraadt 19:
1.7 millert 20: #ifndef TCSASOFT
21: #define TCSASOFT 0
22: #endif
23:
1.1 deraadt 24: char obuf[NOBUF]; /* Output buffer. */
1.8 millert 25: int nobuf; /* Buffer count. */
26: struct termios oldtty; /* POSIX tty settings. */
27: struct termios newtty;
1.1 deraadt 28: int nrow; /* Terminal size, rows. */
29: int ncol; /* Terminal size, columns. */
30:
1.8 millert 31: /*
1.10 millert 32: * This function gets called once, to set up the terminal.
1.8 millert 33: * On systems w/o TCSASOFT we turn off off flow control,
34: * which isn't really the right thing to do.
1.1 deraadt 35: */
1.8 millert 36: void
1.1 deraadt 37: ttopen()
38: {
39:
1.12 ! millert 40: if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))
! 41: panic("standard input and output must be a terminal");
! 42:
1.8 millert 43: if (ttraw() == FALSE)
44: panic("aborting due to terminal initialize failure");
45: }
1.1 deraadt 46:
1.8 millert 47: /*
48: * This function sets the terminal to RAW mode, as defined for the current
49: * shell. This is called both by ttopen() above and by spawncli() to
50: * get the current terminal settings and then change them to what
51: * mg expects. Thus, tty changes done while spawncli() is in effect
52: * will be reflected in mg.
53: */
54: int
55: ttraw()
56: {
57:
58: if (tcgetattr(0, &oldtty) < 0) {
59: ewprintf("ttopen can't get terminal attributes");
60: return(FALSE);
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");
82: return(FALSE);
83: }
1.10 millert 84: return(TRUE);
1.8 millert 85: }
1.1 deraadt 86:
1.8 millert 87: /*
88: * This function gets called just before we go back home to the shell.
89: * Put all of the terminal parameters back.
90: * Under UN*X this just calls ttcooked(), but the ttclose() hook is in
91: * because vttidy() in display.c expects it for portability reasons.
92: */
93: void
94: ttclose()
95: {
1.1 deraadt 96:
1.8 millert 97: if (ttcooked() == FALSE)
98: panic(""); /* ttcooked() already printf'd */
1.1 deraadt 99: }
100:
101: /*
1.8 millert 102: * This function restores all terminal settings to their default values,
103: * in anticipation of exiting or suspending the editor.
1.1 deraadt 104: */
1.8 millert 105: int
106: ttcooked()
1.1 deraadt 107: {
1.8 millert 108:
1.1 deraadt 109: ttflush();
1.8 millert 110: if (tcsetattr(0, TCSASOFT | TCSADRAIN, &oldtty) < 0) {
111: ewprintf("ttclose can't tcsetattr");
112: return(FALSE);
113: }
114: return(TRUE);
1.1 deraadt 115: }
116:
117: /*
1.8 millert 118: * Write character to the display. Characters are buffered up,
119: * to make things a little bit more efficient.
1.1 deraadt 120: */
1.11 millert 121: int
1.1 deraadt 122: ttputc(c)
1.8 millert 123: int c;
1.1 deraadt 124: {
1.5 millert 125:
1.1 deraadt 126: if (nobuf >= NOBUF)
127: ttflush();
128: obuf[nobuf++] = c;
1.11 millert 129: return(c);
1.1 deraadt 130: }
131:
132: /*
133: * Flush output.
134: */
1.8 millert 135: void
1.1 deraadt 136: ttflush()
137: {
1.5 millert 138:
1.1 deraadt 139: if (nobuf != 0) {
1.8 millert 140: if (write(1, obuf, nobuf) != nobuf)
141: panic("ttflush write failed");
1.1 deraadt 142: nobuf = 0;
143: }
144: }
145:
146: /*
147: * Read character from terminal.
148: * All 8 bits are returned, so that you can use
149: * a multi-national terminal.
150: */
1.8 millert 151: int
1.1 deraadt 152: ttgetc()
153: {
1.9 millert 154: char c;
1.5 millert 155:
1.9 millert 156: while (read(0, &c, 1) != 1)
1.5 millert 157: ;
1.9 millert 158: return ((int) c);
1.1 deraadt 159: }
160:
161: /*
1.8 millert 162: * Set the tty size.
163: * XXX - belongs in tty.c since it uses terminfo vars.
1.1 deraadt 164: */
1.8 millert 165: void
1.1 deraadt 166: setttysize()
167: {
168: #ifdef TIOCGWINSZ
1.8 millert 169: struct winsize winsize;
1.5 millert 170:
1.1 deraadt 171: if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
1.5 millert 172: nrow = winsize.ws_row;
173: ncol = winsize.ws_col;
1.8 millert 174: } else nrow = 0;
1.1 deraadt 175: #endif
1.8 millert 176: if ((nrow <= 0 || ncol <= 0) &&
177: ((nrow = lines) <= 0 || (ncol = columns) <= 0)) {
1.1 deraadt 178: nrow = 24;
179: ncol = 80;
180: }
1.4 millert 181:
182: /* Enforce maximum screen size. */
183: if (nrow > NROW)
184: nrow = NROW;
185: if (ncol > NCOL)
1.1 deraadt 186: ncol = NCOL;
187: }
188:
1.8 millert 189: /*
190: * Returns TRUE if there are characters waiting to be read.
191: */
192: int
193: typeahead()
194: {
195: int x;
196:
197: return((ioctl(0, FIONREAD, (char *) &x) < 0) ? 0 : x);
198: }
199:
200: /*
201: * panic - just exit, as quickly as we can.
202: */
1.11 millert 203: VOID
1.8 millert 204: panic(s)
205: char *s;
206: {
207:
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: #ifndef NO_DPROMPT
215: /*
1.8 millert 216: * A program to return TRUE if we wait for 2 seconds without anything
217: * happening, else return FALSE. Cribbed from mod.sources xmodem.
1.1 deraadt 218: */
1.8 millert 219: int
1.1 deraadt 220: ttwait()
221: {
1.8 millert 222: fd_set readfds;
223: struct timeval tmout;
1.5 millert 224:
1.8 millert 225: FD_ZERO(&readfds);
1.5 millert 226: FD_SET(0, &readfds);
227:
228: tmout.tv_sec = 2;
229: tmout.tv_usec = 0;
230:
231: if ((select(1, &readfds, NULL, NULL, &tmout)) == 0)
1.8 millert 232: return (TRUE);
233: return (FALSE);
1.1 deraadt 234: }
1.8 millert 235: #endif /* NO_DPROMPT */