|
|
1.1 root 1: /* unix.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 14407 SW Teal Blvd. #C
6: * Beaverton, OR 97005
7: * [email protected]
8: */
9:
10:
11: /* This file contains the unix-specific versions the ttyread() functions.
12: * There are actually three versions of ttyread() defined here, because
13: * BSD, SysV, and V7 all need quite different implementations.
14: */
15:
16: #include "config.h"
17: #if ANY_UNIX
18: # include "vi.h"
19:
20: # if BSD
21: /* For BSD, we use select() to wait for characters to become available,
22: * and then do a read() to actually get the characters. We also try to
23: * handle SIGWINCH -- if the signal arrives during the select() call, then
24: * we adjust the o_columns and o_lines variables, and fake a control-L.
25: */
26: # include <sys/types.h>
27: # include <sys/time.h>
28: int ttyread(buf, len, time)
29: char *buf; /* where to store the gotten characters */
30: int len; /* maximum number of characters to read */
31: int time; /* maximum time to allow for reading */
32: {
33: fd_set rd; /* the file descriptors that we want to read from */
34: static tty; /* 'y' if reading from tty, or 'n' if not a tty */
35: int i;
36: struct timeval t;
37: struct timeval *tp;
38:
39:
40: /* do we know whether this is a tty or not? */
41: if (!tty)
42: {
43: tty = (isatty(0) ? 'y' : 'n');
44: }
45:
46: /* compute the timeout value */
47: if (time)
48: {
49: t.tv_sec = time / 10;
50: t.tv_usec = (time % 10) * 100000L;
51: tp = &t;
52: }
53: else
54: {
55: tp = (struct timeval *)0;
56: }
57:
58: /* loop until we get characters or a definite EOF */
59: for (;;)
60: {
61: if (tty == 'y')
62: {
63: /* wait until timeout or characters are available */
64: FD_ZERO(&rd);
65: FD_SET(0, &rd);
66: i = select(1, &rd, (fd_set *)0, (fd_set *)0, tp);
67: }
68: else
69: {
70: /* if reading from a file or pipe, never timeout!
71: * (This also affects the way that EOF is detected)
72: */
73: i = 1;
74: }
75:
76: /* react accordingly... */
77: switch (i)
78: {
79: case -1: /* assume we got an EINTR because of SIGWINCH */
80: if (*o_lines != LINES || *o_columns != COLS)
81: {
82: #ifndef CRUNCH
83: *o_nearscroll =
84: #endif
85: *o_lines = LINES;
86: *o_columns = COLS;
87: #ifndef CRUNCH
88: if (!wset)
89: {
90: *o_window = LINES - 1;
91: }
92: #endif
93: if (mode != MODE_EX)
94: {
95: /* pretend the user hit ^L */
96: *buf = ctrl('L');
97: return 1;
98: }
99: }
100: break;
101:
102: case 0: /* timeout */
103: return 0;
104:
105: default: /* characters available */
106: return read(0, buf, len);
107: }
108: }
109: }
110: # else
111:
112: # if M_SYSV || COHERENT
113: /* For System-V or Coherent, we use VMIN/VTIME to implement the timeout.
114: * For no timeout, VMIN should be 1 and VTIME should be 0; for timeout,
115: * VMIN should be 0 and VTIME should be the timeout value.
116: */
117: # include <termio.h>
118: int ttyread(buf, len, time)
119: char *buf; /* where to store the gotten characters */
120: unsigned len; /* maximum number of characters to read */
121: int time; /* maximum time to allow for reading */
122: {
123: struct termio tio;
124: int bytes; /* number of bytes actually read */
125:
126: /* arrange for timeout */
127: ioctl(0, TCGETA, &tio);
128: if (time)
129: {
130: tio.c_cc[VMIN] = 0;
131: tio.c_cc[VTIME] = time;
132: }
133: else
134: {
135: tio.c_cc[VMIN] = 1;
136: tio.c_cc[VTIME] = 0;
137: }
138: ioctl(0, TCSETA, &tio);
139:
140: /* Perform the read. Loop if EINTR error happens */
141: while ((bytes = read(0, buf, len)) < 0)
142: {
143: /* probably EINTR error because a SIGWINCH was received */
144: if (*o_lines != LINES || *o_columns != COLS)
145: {
146: *o_lines = LINES;
147: *o_columns = COLS;
148: #ifndef CRUNCH
149: if (!wset)
150: {
151: *o_nearscroll = *o_window = LINES - 1;
152: }
153: #endif
154: if (mode != MODE_EX)
155: {
156: /* pretend the user hit ^L */
157: *buf = ctrl('L');
158: return 1;
159: }
160: }
161: }
162:
163: /* return the number of bytes read */
164: return bytes;
165:
166: /* NOTE: The terminal may be left in a timeout-mode after this function
167: * returns. This shouldn't be a problem since Elvis *NEVER* tries to
168: * read from the keyboard except through this function.
169: */
170: }
171:
172: # else /* any other version of UNIX, assume it is V7 compatible */
173:
174: /* For V7 UNIX (including Minix) we set an alarm() before doing a blocking
175: * read(), and assume that the SIGALRM signal will cause the read() function
176: * to give up.
177: */
178:
179: #include <setjmp.h>
180:
181: static jmp_buf env;
182:
183: /*ARGSUSED*/
184: int dummy(signo)
185: int signo;
186: {
187: longjmp(env, 1);
188: }
189: int ttyread(buf, len, time)
190: char *buf; /* where to store the gotten characters */
191: int len; /* maximum number of characters to read */
192: int time; /* maximum time to allow for reading */
193: {
194: /* arrange for timeout */
195: #if __GNUC__
196: signal(SIGALRM, (void (*)()) dummy);
197: #else
198: signal(SIGALRM, dummy);
199: #endif
200: alarm(time);
201:
202: /* perform the blocking read */
203: if (setjmp(env) == 0)
204: {
205: len = read(0, buf, len);
206: }
207: else /* I guess we timed out */
208: {
209: len = 0;
210: }
211:
212: /* cancel the alarm */
213: signal(SIGALRM, dummy); /* <-- to work around a bug in Minix */
214: alarm(0);
215:
216: /* return the number of bytes read */
217: if (len < 0)
218: len = 0;
219: return len;
220: }
221:
222: # endif /* !(M_SYSV || COHERENT) */
223: # endif /* !BSD */
224:
225: #endif /* ANY_UNIX */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.