read.c revision 1.8 1 /* $NetBSD: read.c,v 1.8 1998/01/21 10:12:22 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: read.c,v 1.8 1998/01/21 10:12:22 lukem Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49 * read.c: Clean this junk up! This is horrible code.
50 * Terminal read functions
51 */
52 #include "sys.h"
53 #include <sys/errno.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 extern int errno;
57 #include "el.h"
58
59 #define OKCMD -1
60
61 private int read__fixio __P((int, int));
62 private int read_preread __P((EditLine *));
63 private int read_getcmd __P((EditLine *, el_action_t *, char *));
64 private int read_char __P((EditLine *, char *));
65
66 #ifdef DEBUG_EDIT
67 private void
68 read_debug(el)
69 EditLine *el;
70 {
71
72 if (el->el_line.cursor > el->el_line.lastchar)
73 (void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
74 if (el->el_line.cursor < el->el_line.buffer)
75 (void) fprintf(el->el_errfile, "cursor < buffer\r\n");
76 if (el->el_line.cursor > el->el_line.limit)
77 (void) fprintf(el->el_errfile, "cursor > limit\r\n");
78 if (el->el_line.lastchar > el->el_line.limit)
79 (void) fprintf(el->el_errfile, "lastchar > limit\r\n");
80 if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
81 (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
82 }
83 #endif /* DEBUG_EDIT */
84
85 /* read__fixio():
86 * Try to recover from a read error
87 */
88 private int
89 read__fixio(fd, e)
90 int fd, e;
91 {
92 switch (e) {
93 case -1: /* Make sure that the code is reachable */
94
95 #ifdef EWOULDBLOCK
96 case EWOULDBLOCK:
97 # ifndef TRY_AGAIN
98 # define TRY_AGAIN
99 # endif
100 #endif /* EWOULDBLOCK */
101
102 #if defined(POSIX) && defined(EAGAIN)
103 # if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
104 case EAGAIN:
105 # ifndef TRY_AGAIN
106 # define TRY_AGAIN
107 # endif
108 # endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
109 #endif /* POSIX && EAGAIN */
110
111 e = 0;
112 #ifdef TRY_AGAIN
113 # if defined(F_SETFL) && defined(O_NDELAY)
114 if ((e = fcntl(fd, F_GETFL, 0)) == -1)
115 return -1;
116
117 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
118 return -1;
119 else
120 e = 1;
121 # endif /* F_SETFL && O_NDELAY */
122
123 # ifdef FIONBIO
124 {
125 int zero = 0;
126
127 if (ioctl(fd, FIONBIO, (ioctl_t) &zero) == -1)
128 return -1;
129 else
130 e = 1;
131 }
132 # endif /* FIONBIO */
133
134 #endif /* TRY_AGAIN */
135 return e ? 0 : -1;
136
137 case EINTR:
138 return 0;
139
140 default:
141 return -1;
142 }
143 }
144
145
146 /* read_preread():
147 * Try to read the stuff in the input queue;
148 */
149 private int
150 read_preread(el)
151 EditLine *el;
152 {
153 int chrs = 0;
154
155 if (el->el_chared.c_macro.nline) {
156 el_free((ptr_t) el->el_chared.c_macro.nline);
157 el->el_chared.c_macro.nline = NULL;
158 }
159
160 if (el->el_tty.t_mode == ED_IO)
161 return 0;
162
163 #ifdef FIONREAD
164 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
165 if (chrs > 0) {
166 char buf[EL_BUFSIZ];
167
168 chrs = read(el->el_infd, buf, (size_t) MIN(chrs, EL_BUFSIZ - 1));
169 if (chrs > 0) {
170 buf[chrs] = '\0';
171 el->el_chared.c_macro.nline = strdup(buf);
172 el_push(el, el->el_chared.c_macro.nline);
173 }
174 }
175 #endif /* FIONREAD */
176
177 return chrs > 0;
178 }
179
180
181 /* el_push():
182 * Push a macro
183 */
184 public void
185 el_push(el, str)
186 EditLine *el;
187 const char *str;
188 {
189 c_macro_t *ma = &el->el_chared.c_macro;
190
191 if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
192 ma->level++;
193 ma->macro[ma->level] = (char *) str;
194 }
195 else {
196 term_beep(el);
197 term__flush();
198 }
199 }
200
201
202 /* read_getcmd():
203 * Return next command from the input stream.
204 */
205 private int
206 read_getcmd(el, cmdnum, ch)
207 EditLine *el;
208 el_action_t *cmdnum;
209 char *ch;
210 {
211 el_action_t cmd = 0;
212 int num;
213
214 while (cmd == 0 || cmd == ED_SEQUENCE_LEAD_IN) {
215 if ((num = el_getc(el, ch)) != 1) /* if EOF or error */
216 return num;
217
218 #ifdef KANJI
219 if ((*ch & 0200)) {
220 el->el_state.metanext = 0;
221 cmd = CcViMap[' '];
222 break;
223 }
224 else
225 #endif /* KANJI */
226
227 if (el->el_state.metanext) {
228 el->el_state.metanext = 0;
229 *ch |= 0200;
230 }
231 cmd = el->el_map.current[(unsigned char) *ch];
232 if (cmd == ED_SEQUENCE_LEAD_IN) {
233 key_value_t val;
234 switch (key_get(el, ch, &val)) {
235 case XK_CMD:
236 cmd = val.cmd;
237 break;
238 case XK_STR:
239 el_push(el, val.str);
240 break;
241 #ifdef notyet
242 case XK_EXE:
243 /* XXX: In the future to run a user function */
244 RunCommand(val.str);
245 break;
246 #endif
247 default:
248 abort();
249 break;
250 }
251 }
252 if (el->el_map.alt == NULL)
253 el->el_map.current = el->el_map.key;
254 }
255 *cmdnum = cmd;
256 return OKCMD;
257 }
258
259 /* read_char():
260 * Read a character from the tty.
261 */
262 private int
263 read_char(el, cp)
264 EditLine *el;
265 char *cp;
266 {
267 int num_read;
268 int tried = 0;
269
270 while ((num_read = read(el->el_infd, cp, 1)) == -1)
271 if (!tried && read__fixio(el->el_infd, errno) == 0)
272 tried = 1;
273 else {
274 *cp = '\0';
275 return -1;
276 }
277
278 return num_read;
279 }
280
281
282 /* el_getc():
283 * Read a character
284 */
285 public int
286 el_getc(el, cp)
287 EditLine *el;
288 char *cp;
289 {
290 int num_read;
291 c_macro_t *ma = &el->el_chared.c_macro;
292
293 term__flush();
294 for (;;) {
295 if (ma->level < 0) {
296 if (!read_preread(el))
297 break;
298 }
299 if (ma->level < 0)
300 break;
301
302 if (*ma->macro[ma->level] == 0) {
303 ma->level--;
304 continue;
305 }
306 *cp = *ma->macro[ma->level]++ & 0377;
307 if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode On */
308 ma->level--;
309 }
310 return 1;
311 }
312
313 #ifdef DEBUG_READ
314 (void) fprintf(el->el_errfile, "Turning raw mode on\n");
315 #endif /* DEBUG_READ */
316 if (tty_rawmode(el) < 0) /* make sure the tty is set up correctly */
317 return 0;
318
319 #ifdef DEBUG_READ
320 (void) fprintf(el->el_errfile, "Reading a character\n");
321 #endif /* DEBUG_READ */
322 num_read = read_char(el, cp);
323 #ifdef DEBUG_READ
324 (void) fprintf(el->el_errfile, "Got it %c\n", cp);
325 #endif /* DEBUG_READ */
326 return num_read;
327 }
328
329
330
331 public const char *
332 el_gets(el, nread)
333 EditLine *el;
334 int *nread;
335 {
336 int retval;
337 el_action_t cmdnum = 0;
338 int num; /* how many chars we have read at NL */
339 char ch;
340 #ifdef FIONREAD
341 c_macro_t *ma = &el->el_chared.c_macro;
342 #endif /* FIONREAD */
343
344 if (el->el_flags & HANDLE_SIGNALS)
345 sig_set(el);
346
347 if (el->el_flags & NO_TTY) {
348 char *cp = el->el_line.buffer;
349
350 while (read_char(el, cp) == 1) {
351 cp++;
352 if (cp == el->el_line.limit || *cp == '\r' || *cp == '\n') {
353 --cp;
354 break;
355 }
356 }
357 el->el_line.cursor = el->el_line.lastchar = cp;
358 *cp = '\0';
359 if (nread)
360 *nread = el->el_line.cursor - el->el_line.buffer;
361 return el->el_line.buffer;
362 }
363
364 re_clear_display(el); /* reset the display stuff */
365 ch_reset(el);
366
367 #ifdef FIONREAD
368 if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
369 long chrs = 0;
370
371 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs);
372 if (chrs == 0) {
373 if (tty_rawmode(el) < 0) {
374 if (nread)
375 *nread = 0;
376 return NULL;
377 }
378 }
379 }
380 #endif /* FIONREAD */
381
382 re_refresh(el); /* print the prompt */
383
384 for (num = OKCMD; num == OKCMD;) { /* while still editing this line */
385 #ifdef DEBUG_EDIT
386 read_debug(el);
387 #endif /* DEBUG_EDIT */
388 /* if EOF or error */
389 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
390 #ifdef DEBUG_READ
391 (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num);
392 #endif /* DEBUG_READ */
393 break;
394 }
395
396 if (cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
397 #ifdef DEBUG_EDIT
398 (void) fprintf(el->el_errfile,
399 "ERROR: illegal command from key 0%o\r\n", ch);
400 #endif /* DEBUG_EDIT */
401 continue; /* try again */
402 }
403
404 /* now do the real command */
405 #ifdef DEBUG_READ
406 {
407 el_bindings_t *b;
408 for (b = el->el_map.help; b->name; b++)
409 if (b->func == cmdnum)
410 break;
411 if (b->name)
412 (void) fprintf(el->el_errfile, "Executing %s\n", b->name);
413 else
414 (void) fprintf(el->el_errfile, "Error command = %d\n", cmdnum);
415 }
416 #endif /* DEBUG_READ */
417 retval = (*el->el_map.func[cmdnum])(el, ch);
418
419 /* save the last command here */
420 el->el_state.lastcmd = cmdnum;
421
422 /* use any return value */
423 switch (retval) {
424 case CC_CURSOR:
425 el->el_state.argument = 1;
426 el->el_state.doingarg = 0;
427 re_refresh_cursor(el);
428 break;
429
430 case CC_REDISPLAY:
431 re_clear_lines(el);
432 re_clear_display(el);
433 /* FALLTHROUGH */
434
435 case CC_REFRESH:
436 el->el_state.argument = 1;
437 el->el_state.doingarg = 0;
438 re_refresh(el);
439 break;
440
441 case CC_NORM: /* normal char */
442 el->el_state.argument = 1;
443 el->el_state.doingarg = 0;
444 break;
445
446 case CC_ARGHACK: /* Suggested by Rich Salz */
447 /* <rsalz (at) pineapple.bbn.com> */
448 break; /* keep going... */
449
450 case CC_EOF: /* end of file typed */
451 num = 0;
452 break;
453
454 case CC_NEWLINE: /* normal end of line */
455 num = el->el_line.lastchar - el->el_line.buffer;
456 break;
457
458 case CC_FATAL: /* fatal error, reset to known state */
459 #ifdef DEBUG_READ
460 (void) fprintf(el->el_errfile, "*** editor fatal ERROR ***\r\n\n");
461 #endif /* DEBUG_READ */
462 /* put (real) cursor in a known place */
463 re_clear_display(el); /* reset the display stuff */
464 ch_reset(el); /* reset the input pointers */
465 re_refresh(el); /* print the prompt again */
466 el->el_state.argument = 1;
467 el->el_state.doingarg = 0;
468 break;
469
470 case CC_ERROR:
471 default: /* functions we don't know about */
472 #ifdef DEBUG_READ
473 (void) fprintf(el->el_errfile, "*** editor ERROR ***\r\n\n");
474 #endif /* DEBUG_READ */
475 el->el_state.argument = 1;
476 el->el_state.doingarg = 0;
477 term_beep(el);
478 term__flush();
479 break;
480 }
481 }
482
483 (void) tty_cookedmode(el); /* make sure the tty is set up correctly */
484 term__flush(); /* flush any buffered output */
485 if (el->el_flags & HANDLE_SIGNALS)
486 sig_clr(el);
487 if (nread)
488 *nread = num;
489 return num ? el->el_line.buffer : NULL;
490 }
491