This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.bin / elvis / unix.c
CommitLineData
15637ed4
RG
1/* unix.c */
2
3/* Author:
4 * Steve Kirkendall
5 * 14407 SW Teal Blvd. #C
6 * Beaverton, OR 97005
7 * kirkenda@cs.pdx.edu
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>
28int 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 {
78ed81a3 82#ifndef CRUNCH
83 *o_nearscroll =
84#endif
15637ed4
RG
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
78ed81a3 112# if UNIXV || COH_386
113/* For System-V, we use VMIN/VTIME to implement the timeout. For no timeout,
114 * VMIN should be 1 and VTIME should be 0; for timeout, VMIN should be 0 and
115 * VTIME should be the timeout value.
15637ed4
RG
116 */
117# include <termio.h>
118int ttyread(buf, len, time)
119 char *buf; /* where to store the gotten characters */
120 int 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 */
78ed81a3 141 while ((bytes = read(0, buf, (unsigned)len)) < 0)
15637ed4
RG
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 {
78ed81a3 151 *o_nearscroll = LINES;
15637ed4
RG
152 *o_window = LINES - 1;
153 }
154#endif
155 if (mode != MODE_EX)
156 {
157 /* pretend the user hit ^L */
158 *buf = ctrl('L');
159 return 1;
160 }
161 }
162 }
163
164 /* return the number of bytes read */
165 return bytes;
166
167 /* NOTE: The terminal may be left in a timeout-mode after this function
168 * returns. This shouldn't be a problem since Elvis *NEVER* tries to
169 * read from the keyboard except through this function.
170 */
171}
172
173# else /* any other version of UNIX, assume it is V7 compatible */
174
175/* For V7 UNIX (including Minix) we set an alarm() before doing a blocking
176 * read(), and assume that the SIGALRM signal will cause the read() function
177 * to give up.
178 */
179
180#include <setjmp.h>
181
182static jmp_buf env;
183
184/*ARGSUSED*/
78ed81a3 185SIGTYPE dummy(signo)
15637ed4
RG
186 int signo;
187{
188 longjmp(env, 1);
189}
190int ttyread(buf, len, time)
191 char *buf; /* where to store the gotten characters */
192 int len; /* maximum number of characters to read */
193 int time; /* maximum time to allow for reading */
194{
195 /* arrange for timeout */
15637ed4 196 signal(SIGALRM, dummy);
15637ed4
RG
197 alarm(time);
198
199 /* perform the blocking read */
200 if (setjmp(env) == 0)
201 {
78ed81a3 202 len = read(0, buf, (unsigned)len);
15637ed4
RG
203 }
204 else /* I guess we timed out */
205 {
206 len = 0;
207 }
208
209 /* cancel the alarm */
210 signal(SIGALRM, dummy); /* <-- to work around a bug in Minix */
211 alarm(0);
212
213 /* return the number of bytes read */
214 if (len < 0)
215 len = 0;
216 return len;
217}
218
78ed81a3 219# endif /* M_SYSV */
15637ed4
RG
220# endif /* !BSD */
221
222#endif /* ANY_UNIX */