read.c revision 1.28 1 /* $NetBSD: read.c,v 1.28 2003/09/26 17:44:51 christos 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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: read.c,v 1.28 2003/09/26 17:44:51 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43
44 /*
45 * read.c: Clean this junk up! This is horrible code.
46 * Terminal read functions
47 */
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include "el.h"
53
54 #define OKCMD -1
55
56 private int read__fixio(int, int);
57 private int read_preread(EditLine *);
58 private int read_char(EditLine *, char *);
59 private int read_getcmd(EditLine *, el_action_t *, char *);
60
61 /* read_init():
62 * Initialize the read stuff
63 */
64 protected int
65 read_init(EditLine *el)
66 {
67 /* builtin read_char */
68 el->el_read.read_char = read_char;
69 return 0;
70 }
71
72
73 /* el_read_setfn():
74 * Set the read char function to the one provided.
75 * If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
76 */
77 protected int
78 el_read_setfn(EditLine *el, el_rfunc_t rc)
79 {
80 el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
81 return 0;
82 }
83
84
85 /* el_read_getfn():
86 * return the current read char function, or EL_BUILTIN_GETCFN
87 * if it is the default one
88 */
89 protected el_rfunc_t
90 el_read_getfn(EditLine *el)
91 {
92 return (el->el_read.read_char == read_char) ?
93 EL_BUILTIN_GETCFN : el->el_read.read_char;
94 }
95
96
97 #ifndef MIN
98 #define MIN(A,B) ((A) < (B) ? (A) : (B))
99 #endif
100
101 #ifdef DEBUG_EDIT
102 private void
103 read_debug(EditLine *el)
104 {
105
106 if (el->el_line.cursor > el->el_line.lastchar)
107 (void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
108 if (el->el_line.cursor < el->el_line.buffer)
109 (void) fprintf(el->el_errfile, "cursor < buffer\r\n");
110 if (el->el_line.cursor > el->el_line.limit)
111 (void) fprintf(el->el_errfile, "cursor > limit\r\n");
112 if (el->el_line.lastchar > el->el_line.limit)
113 (void) fprintf(el->el_errfile, "lastchar > limit\r\n");
114 if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
115 (void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
116 }
117 #endif /* DEBUG_EDIT */
118
119
120 /* read__fixio():
121 * Try to recover from a read error
122 */
123 /* ARGSUSED */
124 private int
125 read__fixio(int fd __attribute__((__unused__)), int e)
126 {
127
128 switch (e) {
129 case -1: /* Make sure that the code is reachable */
130
131 #ifdef EWOULDBLOCK
132 case EWOULDBLOCK:
133 #ifndef TRY_AGAIN
134 #define TRY_AGAIN
135 #endif
136 #endif /* EWOULDBLOCK */
137
138 #if defined(POSIX) && defined(EAGAIN)
139 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
140 case EAGAIN:
141 #ifndef TRY_AGAIN
142 #define TRY_AGAIN
143 #endif
144 #endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
145 #endif /* POSIX && EAGAIN */
146
147 e = 0;
148 #ifdef TRY_AGAIN
149 #if defined(F_SETFL) && defined(O_NDELAY)
150 if ((e = fcntl(fd, F_GETFL, 0)) == -1)
151 return (-1);
152
153 if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
154 return (-1);
155 else
156 e = 1;
157 #endif /* F_SETFL && O_NDELAY */
158
159 #ifdef FIONBIO
160 {
161 int zero = 0;
162
163 if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -1)
164 return (-1);
165 else
166 e = 1;
167 }
168 #endif /* FIONBIO */
169
170 #endif /* TRY_AGAIN */
171 return (e ? 0 : -1);
172
173 case EINTR:
174 return (0);
175
176 default:
177 return (-1);
178 }
179 }
180
181
182 /* read_preread():
183 * Try to read the stuff in the input queue;
184 */
185 private int
186 read_preread(EditLine *el)
187 {
188 int chrs = 0;
189
190 if (el->el_chared.c_macro.nline) {
191 el_free((ptr_t) el->el_chared.c_macro.nline);
192 el->el_chared.c_macro.nline = NULL;
193 }
194 if (el->el_tty.t_mode == ED_IO)
195 return (0);
196
197 #ifdef FIONREAD
198 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
199 if (chrs > 0) {
200 char buf[EL_BUFSIZ];
201
202 chrs = read(el->el_infd, buf,
203 (size_t) MIN(chrs, EL_BUFSIZ - 1));
204 if (chrs > 0) {
205 buf[chrs] = '\0';
206 el->el_chared.c_macro.nline = strdup(buf);
207 el_push(el, el->el_chared.c_macro.nline);
208 }
209 }
210 #endif /* FIONREAD */
211
212 return (chrs > 0);
213 }
214
215
216 /* el_push():
217 * Push a macro
218 */
219 public void
220 el_push(EditLine *el, char *str)
221 {
222 c_macro_t *ma = &el->el_chared.c_macro;
223
224 if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
225 ma->level++;
226 ma->macro[ma->level] = str;
227 } else {
228 term_beep(el);
229 term__flush();
230 }
231 }
232
233
234 /* read_getcmd():
235 * Return next command from the input stream.
236 */
237 private int
238 read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch)
239 {
240 el_action_t cmd;
241 int num;
242
243 do {
244 if ((num = el_getc(el, ch)) != 1) /* if EOF or error */
245 return (num);
246
247 #ifdef KANJI
248 if ((*ch & 0200)) {
249 el->el_state.metanext = 0;
250 cmd = CcViMap[' '];
251 break;
252 } else
253 #endif /* KANJI */
254
255 if (el->el_state.metanext) {
256 el->el_state.metanext = 0;
257 *ch |= 0200;
258 }
259 cmd = el->el_map.current[(unsigned char) *ch];
260 if (cmd == ED_SEQUENCE_LEAD_IN) {
261 key_value_t val;
262 switch (key_get(el, ch, &val)) {
263 case XK_CMD:
264 cmd = val.cmd;
265 break;
266 case XK_STR:
267 el_push(el, val.str);
268 break;
269 #ifdef notyet
270 case XK_EXE:
271 /* XXX: In the future to run a user function */
272 RunCommand(val.str);
273 break;
274 #endif
275 default:
276 EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
277 break;
278 }
279 }
280 if (el->el_map.alt == NULL)
281 el->el_map.current = el->el_map.key;
282 } while (cmd == ED_SEQUENCE_LEAD_IN);
283 *cmdnum = cmd;
284 return (OKCMD);
285 }
286
287
288 /* read_char():
289 * Read a character from the tty.
290 */
291 private int
292 read_char(EditLine *el, char *cp)
293 {
294 int num_read;
295 int tried = 0;
296
297 while ((num_read = read(el->el_infd, cp, 1)) == -1)
298 if (!tried && read__fixio(el->el_infd, errno) == 0)
299 tried = 1;
300 else {
301 *cp = '\0';
302 return (-1);
303 }
304
305 return (num_read);
306 }
307
308
309 /* el_getc():
310 * Read a character
311 */
312 public int
313 el_getc(EditLine *el, char *cp)
314 {
315 int num_read;
316 c_macro_t *ma = &el->el_chared.c_macro;
317
318 term__flush();
319 for (;;) {
320 if (ma->level < 0) {
321 if (!read_preread(el))
322 break;
323 }
324 if (ma->level < 0)
325 break;
326
327 if (*ma->macro[ma->level] == 0) {
328 ma->level--;
329 continue;
330 }
331 *cp = *ma->macro[ma->level]++ & 0377;
332 if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode
333 * On */
334 ma->level--;
335 }
336 return (1);
337 }
338
339 #ifdef DEBUG_READ
340 (void) fprintf(el->el_errfile, "Turning raw mode on\n");
341 #endif /* DEBUG_READ */
342 if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
343 return (0);
344
345 #ifdef DEBUG_READ
346 (void) fprintf(el->el_errfile, "Reading a character\n");
347 #endif /* DEBUG_READ */
348 num_read = (*el->el_read.read_char)(el, cp);
349 #ifdef DEBUG_READ
350 (void) fprintf(el->el_errfile, "Got it %c\n", *cp);
351 #endif /* DEBUG_READ */
352 return (num_read);
353 }
354
355 protected void
356 read_prepare(EditLine *el)
357 {
358 if (el->el_flags & HANDLE_SIGNALS)
359 sig_set(el);
360 if (el->el_flags & NO_TTY)
361 return;
362 if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
363 tty_rawmode(el);
364
365 /* This is relatively cheap, and things go terribly wrong if
366 we have the wrong size. */
367 el_resize(el);
368 re_clear_display(el); /* reset the display stuff */
369 ch_reset(el);
370 re_refresh(el); /* print the prompt */
371 }
372
373 protected void
374 read_finish(EditLine *el)
375 {
376 if ((el->el_flags & UNBUFFERED) == 0)
377 (void) tty_cookedmode(el);
378 if (el->el_flags & HANDLE_SIGNALS)
379 sig_clr(el);
380 }
381
382 public const char *
383 el_gets(EditLine *el, int *nread)
384 {
385 int retval;
386 el_action_t cmdnum = 0;
387 int num; /* how many chars we have read at NL */
388 char ch;
389 int crlf = 0;
390 #ifdef FIONREAD
391 c_macro_t *ma = &el->el_chared.c_macro;
392 #endif /* FIONREAD */
393
394 if (el->el_flags & NO_TTY) {
395 char *cp = el->el_line.buffer;
396 size_t idx;
397
398 while ((*el->el_read.read_char)(el, cp) == 1) {
399 /* make sure there is space for next character */
400 if (cp + 1 >= el->el_line.limit) {
401 idx = (cp - el->el_line.buffer);
402 if (!ch_enlargebufs(el, 2))
403 break;
404 cp = &el->el_line.buffer[idx];
405 }
406 cp++;
407 if (el->el_flags & UNBUFFERED)
408 break;
409 if (cp[-1] == '\r' || cp[-1] == '\n')
410 break;
411 }
412
413 el->el_line.cursor = el->el_line.lastchar = cp;
414 *cp = '\0';
415 if (nread)
416 *nread = el->el_line.cursor - el->el_line.buffer;
417 return (el->el_line.buffer);
418 }
419
420
421 #ifdef FIONREAD
422 if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
423 long chrs = 0;
424
425 (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
426 if (chrs == 0) {
427 if (tty_rawmode(el) < 0) {
428 if (nread)
429 *nread = 0;
430 return (NULL);
431 }
432 }
433 }
434 #endif /* FIONREAD */
435
436 if ((el->el_flags & UNBUFFERED) == 0)
437 read_prepare(el);
438
439 if (el->el_flags & EDIT_DISABLED) {
440 char *cp = el->el_line.buffer;
441 size_t idx;
442
443 term__flush();
444
445 while ((*el->el_read.read_char)(el, cp) == 1) {
446 /* make sure there is space next character */
447 if (cp + 1 >= el->el_line.limit) {
448 idx = (cp - el->el_line.buffer);
449 if (!ch_enlargebufs(el, 2))
450 break;
451 cp = &el->el_line.buffer[idx];
452 }
453 if (*cp == 4) /* ought to be stty eof */
454 break;
455 cp++;
456 crlf = cp[-1] == '\r' || cp[-1] == '\n';
457 if (el->el_flags & UNBUFFERED)
458 break;
459 if (crlf)
460 break;
461 }
462
463 el->el_line.cursor = el->el_line.lastchar = cp;
464 *cp = '\0';
465 if (nread)
466 *nread = el->el_line.cursor - el->el_line.buffer;
467 return (el->el_line.buffer);
468 }
469
470 for (num = OKCMD; num == OKCMD;) { /* while still editing this
471 * line */
472 #ifdef DEBUG_EDIT
473 read_debug(el);
474 #endif /* DEBUG_EDIT */
475 /* if EOF or error */
476 if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
477 #ifdef DEBUG_READ
478 (void) fprintf(el->el_errfile,
479 "Returning from el_gets %d\n", num);
480 #endif /* DEBUG_READ */
481 break;
482 }
483 if ((uint)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
484 #ifdef DEBUG_EDIT
485 (void) fprintf(el->el_errfile,
486 "ERROR: illegal command from key 0%o\r\n", ch);
487 #endif /* DEBUG_EDIT */
488 continue; /* try again */
489 }
490 /* now do the real command */
491 #ifdef DEBUG_READ
492 {
493 el_bindings_t *b;
494 for (b = el->el_map.help; b->name; b++)
495 if (b->func == cmdnum)
496 break;
497 if (b->name)
498 (void) fprintf(el->el_errfile,
499 "Executing %s\n", b->name);
500 else
501 (void) fprintf(el->el_errfile,
502 "Error command = %d\n", cmdnum);
503 }
504 #endif /* DEBUG_READ */
505 /* vi redo needs these way down the levels... */
506 el->el_state.thiscmd = cmdnum;
507 el->el_state.thisch = ch;
508 if (el->el_map.type == MAP_VI &&
509 el->el_map.current == el->el_map.key &&
510 el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
511 if (cmdnum == VI_DELETE_PREV_CHAR &&
512 el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
513 && isprint(el->el_chared.c_redo.pos[-1]))
514 el->el_chared.c_redo.pos--;
515 else
516 *el->el_chared.c_redo.pos++ = ch;
517 }
518 retval = (*el->el_map.func[cmdnum]) (el, ch);
519 #ifdef DEBUG_READ
520 (void) fprintf(el->el_errfile,
521 "Returned state %d\n", retval );
522 #endif /* DEBUG_READ */
523
524 /* save the last command here */
525 el->el_state.lastcmd = cmdnum;
526
527 /* use any return value */
528 switch (retval) {
529 case CC_CURSOR:
530 re_refresh_cursor(el);
531 break;
532
533 case CC_REDISPLAY:
534 re_clear_lines(el);
535 re_clear_display(el);
536 /* FALLTHROUGH */
537
538 case CC_REFRESH:
539 re_refresh(el);
540 break;
541
542 case CC_REFRESH_BEEP:
543 re_refresh(el);
544 term_beep(el);
545 break;
546
547 case CC_NORM: /* normal char */
548 break;
549
550 case CC_ARGHACK: /* Suggested by Rich Salz */
551 /* <rsalz (at) pineapple.bbn.com> */
552 continue; /* keep going... */
553
554 case CC_EOF: /* end of file typed */
555 num = 0;
556 break;
557
558 case CC_NEWLINE: /* normal end of line */
559 num = el->el_line.lastchar - el->el_line.buffer;
560 break;
561
562 case CC_FATAL: /* fatal error, reset to known state */
563 #ifdef DEBUG_READ
564 (void) fprintf(el->el_errfile,
565 "*** editor fatal ERROR ***\r\n\n");
566 #endif /* DEBUG_READ */
567 /* put (real) cursor in a known place */
568 re_clear_display(el); /* reset the display stuff */
569 ch_reset(el); /* reset the input pointers */
570 re_refresh(el); /* print the prompt again */
571 break;
572
573 case CC_ERROR:
574 default: /* functions we don't know about */
575 #ifdef DEBUG_READ
576 (void) fprintf(el->el_errfile,
577 "*** editor ERROR ***\r\n\n");
578 #endif /* DEBUG_READ */
579 term_beep(el);
580 term__flush();
581 break;
582 }
583 el->el_state.argument = 1;
584 el->el_state.doingarg = 0;
585 el->el_chared.c_vcmd.action = NOP;
586 if (el->el_flags & UNBUFFERED)
587 break;
588 }
589
590 term__flush(); /* flush any buffered output */
591 /* make sure the tty is set up correctly */
592 if ((el->el_flags & UNBUFFERED) == 0) {
593 read_finish(el);
594 if (nread)
595 *nread = num;
596 } else {
597 if (nread)
598 *nread = el->el_line.lastchar - el->el_line.buffer;
599 }
600 return (num ? el->el_line.buffer : NULL);
601 }
602