Commit | Line | Data |
---|---|---|
188802ca KB |
1 | /*- |
2 | * Copyright (c) 1992 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Christos Zoulas of Cornell University. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | */ | |
10 | ||
b6dd18ed CZ |
11 | #if !defined(lint) && !defined(SCCSID) |
12 | static char sccsid[] = "@(#)read.c 5.2 (Berkeley) %G%"; | |
188802ca | 13 | |
b6dd18ed | 14 | #endif /* not lint && not SCCSID */ |
188802ca | 15 | /* |
b6dd18ed CZ |
16 | * read.c: Clean this junk up! This is horrible code. |
17 | * Terminal read functions | |
188802ca KB |
18 | */ |
19 | #include "sys.h" | |
20 | #include <sys/errno.h> | |
21 | #include <unistd.h> | |
22 | #include <stdlib.h> | |
23 | extern int errno; | |
24 | #include "el.h" | |
25 | ||
26 | #define OKCMD -1 | |
27 | ||
b6dd18ed CZ |
28 | private int read__fixio __P((int, int)); |
29 | private int read_preread __P((EditLine *)); | |
30 | private int read_getcmd __P((EditLine *, el_action_t *, char *)); | |
31 | ||
188802ca KB |
32 | #ifdef DEBUG_EDIT |
33 | private void | |
34 | read_debug(el) | |
35 | EditLine *el; | |
36 | { | |
37 | ||
38 | if (el->el_line.cursor > el->el_line.lastchar) | |
39 | (void) fprintf(el->el_errfile, "cursor > lastchar\r\n"); | |
40 | if (el->el_line.cursor < el->el_line.buffer) | |
41 | (void) fprintf(el->el_errfile, "cursor < buffer\r\n"); | |
42 | if (el->el_line.cursor > el->el_line.limit) | |
43 | (void) fprintf(el->el_errfile, "cursor > limit\r\n"); | |
44 | if (el->el_line.lastchar > el->el_line.limit) | |
45 | (void) fprintf(el->el_errfile, "lastchar > limit\r\n"); | |
46 | if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2]) | |
47 | (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n"); | |
188802ca | 48 | } |
b6dd18ed | 49 | #endif /* DEBUG_EDIT */ |
188802ca | 50 | |
b6dd18ed CZ |
51 | /* read__fixio(): |
52 | * Try to recover from a read error | |
53 | */ | |
54 | private int | |
55 | read__fixio(fd, e) | |
56 | int fd, e; | |
188802ca | 57 | { |
b6dd18ed CZ |
58 | switch (e) { |
59 | case -1: /* Make sure that the code is reachable */ | |
188802ca | 60 | |
b6dd18ed CZ |
61 | #ifdef EWOULDBLOCK |
62 | case EWOULDBLOCK: | |
63 | # define TRY_AGAIN | |
64 | #endif /* EWOULDBLOCK */ | |
188802ca | 65 | |
b6dd18ed CZ |
66 | #if defined(POSIX) && defined(EAGAIN) |
67 | # if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN | |
68 | case EAGAIN: | |
69 | # define TRY_AGAIN | |
70 | # endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ | |
71 | #endif /* POSIX && EAGAIN */ | |
72 | ||
73 | e = 0; | |
74 | #ifdef TRY_AGAIN | |
75 | # if defined(F_SETFL) && defined(O_NDELAY) | |
76 | if ((e = fcntl(fd, F_GETFL, 0)) == -1) | |
77 | return -1; | |
78 | ||
79 | if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1) | |
80 | return -1; | |
81 | else | |
82 | e = 1; | |
83 | # endif /* F_SETFL && O_NDELAY */ | |
84 | ||
85 | # ifdef FIONBIO | |
86 | if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1) | |
87 | return -1; | |
88 | else | |
89 | e = 1; | |
90 | # endif /* FIONBIO */ | |
91 | ||
92 | #endif /* TRY_AGAIN */ | |
93 | return e ? 0 : -1; | |
94 | ||
95 | case EINTR: | |
96 | return 0; | |
97 | ||
98 | default: | |
99 | return -1; | |
100 | } | |
101 | } | |
102 | ||
103 | ||
104 | /* read_preread(): | |
105 | * Try to read the stuff in the input queue; | |
106 | */ | |
107 | private int | |
108 | read_preread(el) | |
109 | EditLine *el; | |
110 | { | |
111 | int chrs = 0; | |
112 | ||
113 | if (el->el_chared.c_macro.nline) { | |
114 | el_free((ptr_t) el->el_chared.c_macro.nline); | |
115 | el->el_chared.c_macro.nline = NULL; | |
116 | } | |
117 | ||
118 | if (el->el_tty.t_mode == ED_IO) | |
188802ca KB |
119 | return 0; |
120 | ||
121 | #ifdef FIONREAD | |
b6dd18ed | 122 | (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs); |
188802ca | 123 | if (chrs > 0) { |
b6dd18ed | 124 | char buf[EL_BUFSIZ]; |
188802ca | 125 | |
b6dd18ed | 126 | chrs = read(el->el_infd, buf, (size_t) MIN(chrs, EL_BUFSIZ - 1)); |
188802ca KB |
127 | if (chrs > 0) { |
128 | buf[chrs] = '\0'; | |
b6dd18ed CZ |
129 | el->el_chared.c_macro.nline = strdup(buf); |
130 | el_push(el->el_chared.c_macro.nline); | |
188802ca KB |
131 | } |
132 | } | |
133 | #endif /* FIONREAD */ | |
b6dd18ed | 134 | |
188802ca KB |
135 | return chrs > 0; |
136 | } | |
188802ca KB |
137 | |
138 | ||
139 | /* el_push(): | |
140 | * Push a macro | |
141 | */ | |
142 | public void | |
143 | el_push(el, str) | |
144 | EditLine *el; | |
145 | const char *str; | |
146 | { | |
147 | c_macro_t *ma = &el->el_chared.c_macro; | |
148 | ||
149 | if (str != NULL && ma->level + 1 < EL_MAXMACRO) { | |
150 | ma->level++; | |
151 | ma->macro[ma->level] = (char *) str; | |
152 | } | |
153 | else { | |
154 | term_beep(el); | |
155 | term__flush(); | |
156 | } | |
157 | } | |
158 | ||
b6dd18ed CZ |
159 | |
160 | /* read_getcmd(): | |
161 | * Return next command from the input stream. | |
162 | */ | |
188802ca | 163 | private int |
b6dd18ed | 164 | read_getcmd(el, cmdnum, ch) |
188802ca KB |
165 | EditLine *el; |
166 | el_action_t *cmdnum; | |
167 | char *ch; | |
168 | { | |
169 | el_action_t cmd = 0; | |
170 | int num; | |
171 | ||
172 | while (cmd == 0 || cmd == ED_SEQUENCE_LEAD_IN) { | |
173 | if ((num = el_getc(el, ch)) != 1) /* if EOF or error */ | |
174 | return num; | |
175 | ||
176 | #ifdef KANJI | |
177 | if ((*ch & 0200)) { | |
178 | el->el_state.metanext = 0; | |
179 | cmd = CcViMap[' ']; | |
180 | break; | |
181 | } | |
182 | else | |
183 | #endif /* KANJI */ | |
184 | ||
185 | if (el->el_state.metanext) { | |
186 | el->el_state.metanext = 0; | |
187 | *ch |= 0200; | |
188 | } | |
189 | cmd = el->el_map.current[(unsigned char) *ch]; | |
190 | if (cmd == ED_SEQUENCE_LEAD_IN) { | |
191 | key_value_t val; | |
192 | switch (key_get(el, ch, &val)) { | |
193 | case XK_CMD: | |
194 | cmd = val.cmd; | |
195 | break; | |
196 | case XK_STR: | |
197 | el_push(el, val.str); | |
198 | break; | |
199 | #ifdef notyet | |
200 | case XK_EXE: | |
201 | /* XXX: In the future to run a user function */ | |
202 | RunCommand(val.str); | |
203 | break; | |
204 | #endif | |
205 | default: | |
206 | abort(); | |
207 | break; | |
208 | } | |
209 | } | |
210 | if (el->el_map.alt == NULL) | |
211 | el->el_map.current = el->el_map.key; | |
212 | } | |
213 | *cmdnum = cmd; | |
214 | return OKCMD; | |
215 | } | |
216 | ||
217 | ||
218 | /* el_getc(): | |
219 | * Read a character | |
220 | */ | |
221 | public int | |
222 | el_getc(el, cp) | |
223 | EditLine *el; | |
224 | char *cp; | |
225 | { | |
226 | int num_read; | |
188802ca | 227 | unsigned char tcp; |
b6dd18ed | 228 | int tried = 0; |
188802ca KB |
229 | |
230 | c_macro_t *ma = &el->el_chared.c_macro; | |
231 | ||
232 | term__flush(); | |
233 | for (;;) { | |
188802ca | 234 | if (ma->level < 0) { |
b6dd18ed | 235 | if (!read_preread(el)) |
188802ca KB |
236 | break; |
237 | } | |
188802ca KB |
238 | if (ma->level < 0) |
239 | break; | |
240 | ||
241 | if (*ma->macro[ma->level] == 0) { | |
242 | ma->level--; | |
243 | continue; | |
244 | } | |
245 | *cp = *ma->macro[ma->level]++ & 0377; | |
246 | if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode On */ | |
247 | ma->level--; | |
248 | } | |
249 | return 1; | |
250 | } | |
251 | ||
252 | #ifdef DEBUG_READ | |
253 | (void) fprintf(el->el_errfile, "Turning raw mode on\n"); | |
b6dd18ed | 254 | #endif /* DEBUG_READ */ |
188802ca | 255 | if (tty_rawmode(el) < 0) /* make sure the tty is set up correctly */ |
b6dd18ed | 256 | return 0; |
188802ca KB |
257 | |
258 | #ifdef DEBUG_READ | |
259 | (void) fprintf(el->el_errfile, "Reading a character\n"); | |
b6dd18ed | 260 | #endif /* DEBUG_READ */ |
188802ca | 261 | while ((num_read = read(el->el_infd, (char *) &tcp, 1)) == -1) |
b6dd18ed CZ |
262 | if (!tried && read__fixio(el->el_infd, errno) == 0) |
263 | tried = 1; | |
264 | else { | |
265 | *cp = '\0'; | |
266 | return -1; | |
188802ca KB |
267 | } |
268 | #ifdef DEBUG_READ | |
269 | (void) fprintf(el->el_errfile, "Got it %c\n", tcp); | |
b6dd18ed | 270 | #endif /* DEBUG_READ */ |
188802ca KB |
271 | *cp = tcp; |
272 | return num_read; | |
273 | } | |
274 | ||
275 | ||
276 | ||
277 | public const char * | |
278 | el_gets(el, nread) | |
279 | EditLine *el; | |
280 | int *nread; | |
281 | { | |
282 | int retval; | |
283 | el_action_t cmdnum = 0; | |
284 | int num; /* how many chars we have read at NL */ | |
285 | char ch; | |
286 | ||
287 | if (el->el_flags & HANDLE_SIGNALS) | |
288 | sig_set(el); | |
289 | ||
290 | re_clear_display(el); /* reset the display stuff */ | |
291 | ch_reset(el); | |
292 | ||
188802ca | 293 | #ifdef FIONREAD |
b6dd18ed | 294 | if (el->el_tty.t_mode == EX_IO && ma->level < 0) { |
188802ca KB |
295 | long chrs = 0; |
296 | ||
b6dd18ed | 297 | (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs); |
188802ca KB |
298 | if (chrs == 0) { |
299 | if (tty_rawmode(el) < 0) { | |
300 | if (nread) | |
301 | *nread = 0; | |
302 | return NULL; | |
303 | } | |
304 | } | |
305 | } | |
b6dd18ed | 306 | #endif /* FIONREAD */ |
188802ca KB |
307 | |
308 | re_refresh(el); /* print the prompt */ | |
309 | ||
310 | for (num = OKCMD; num == OKCMD;) { /* while still editing this line */ | |
311 | #ifdef DEBUG_EDIT | |
312 | read_debug(el); | |
b6dd18ed | 313 | #endif /* DEBUG_EDIT */ |
188802ca | 314 | /* if EOF or error */ |
b6dd18ed | 315 | if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { |
188802ca KB |
316 | #ifdef DEBUG_READ |
317 | (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num); | |
b6dd18ed | 318 | #endif /* DEBUG_READ */ |
188802ca KB |
319 | break; |
320 | } | |
321 | ||
322 | if (cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ | |
323 | #ifdef DEBUG_EDIT | |
b6dd18ed CZ |
324 | (void) fprintf(el->el_errfile, |
325 | "ERROR: illegal command from key 0%o\r\n", ch); | |
326 | #endif /* DEBUG_EDIT */ | |
188802ca KB |
327 | continue; /* try again */ |
328 | } | |
329 | ||
330 | /* now do the real command */ | |
331 | #ifdef DEBUG_READ | |
332 | { | |
333 | el_bindings_t *b; | |
334 | for (b = el->el_map.help; b->name; b++) | |
335 | if (b->func == cmdnum) | |
336 | break; | |
337 | if (b->name) | |
338 | (void) fprintf(el->el_errfile, "Executing %s\n", b->name); | |
339 | else | |
340 | (void) fprintf(el->el_errfile, "Error command = %d\n", cmdnum); | |
341 | } | |
b6dd18ed | 342 | #endif /* DEBUG_READ */ |
188802ca KB |
343 | retval = (*el->el_map.func[cmdnum])(el, ch); |
344 | ||
345 | /* save the last command here */ | |
346 | el->el_state.lastcmd = cmdnum; | |
347 | ||
348 | /* use any return value */ | |
349 | switch (retval) { | |
350 | case CC_CURSOR: | |
351 | el->el_state.argument = 1; | |
352 | el->el_state.doingarg = 0; | |
353 | re_refresh_cursor(el); | |
354 | break; | |
355 | ||
356 | case CC_REFRESH: | |
357 | el->el_state.argument = 1; | |
358 | el->el_state.doingarg = 0; | |
359 | re_refresh(el); | |
360 | break; | |
361 | ||
362 | case CC_NORM: /* normal char */ | |
363 | el->el_state.argument = 1; | |
364 | el->el_state.doingarg = 0; | |
365 | break; | |
366 | ||
367 | case CC_ARGHACK: /* Suggested by Rich Salz */ | |
368 | /* <rsalz@pineapple.bbn.com> */ | |
369 | break; /* keep going... */ | |
370 | ||
371 | case CC_EOF: /* end of file typed */ | |
372 | num = 0; | |
373 | break; | |
374 | ||
375 | case CC_NEWLINE: /* normal end of line */ | |
376 | num = el->el_line.lastchar - el->el_line.buffer; | |
188802ca KB |
377 | break; |
378 | ||
379 | case CC_FATAL: /* fatal error, reset to known state */ | |
380 | #ifdef DEBUG_READ | |
381 | (void) fprintf(el->el_errfile, "*** editor fatal ERROR ***\r\n\n"); | |
382 | #endif /* DEBUG_READ */ | |
383 | /* put (real) cursor in a known place */ | |
384 | re_clear_display(el); /* reset the display stuff */ | |
385 | ch_reset(el); /* reset the input pointers */ | |
386 | re_refresh(el); /* print the prompt again */ | |
387 | el->el_state.argument = 1; | |
388 | el->el_state.doingarg = 0; | |
389 | break; | |
390 | ||
391 | case CC_ERROR: | |
392 | default: /* functions we don't know about */ | |
393 | #ifdef DEBUG_READ | |
394 | (void) fprintf(el->el_errfile, "*** editor ERROR ***\r\n\n"); | |
b6dd18ed | 395 | #endif /* DEBUG_READ */ |
188802ca KB |
396 | el->el_state.argument = 1; |
397 | el->el_state.doingarg = 0; | |
398 | term_beep(el); | |
399 | term__flush(); | |
400 | break; | |
401 | } | |
402 | } | |
403 | ||
404 | (void) tty_cookedmode(el); /* make sure the tty is set up correctly */ | |
405 | term__flush(); /* flush any buffered output */ | |
406 | if (el->el_flags & HANDLE_SIGNALS) | |
407 | sig_clr(el); | |
408 | if (nread) | |
409 | *nread = num; | |
410 | return num ? el->el_line.buffer : NULL; | |
411 | } |